__toString Alternative

Parantatatam

mag Cookies & Kekse
Hallo,

ich habe gerade das Problem, dass wenn ich die Variable (die Instanz) einer Klasse per var_dump() ausgebe, dass mir ja dann die ganzen Variablen (egal ob private, public oder protected) ausgeben werden. Für Zeichenketten gibt es ja da die Funktion __toString() - gibt es so etwas auch für alle anderen Typen die zurückgegeben werden könnten?

Danke schon im Voraus :)
 
Hallo,

__toString() wird als Methode aufgerufen, wenn man

PHP:
echo $object;

ausführt.

Andere magische Methoden würden an dieser Stelle keinen Sinn machen. Obwohl ich das auch manchmal gern hätte, wenn an es so schreiben könnte, das ein Array aller public Member-Variablen zurückgeben würde.

Allerdings kann man das ja auch in der Klasse implementieren und dann manuell aufrufen.

Was genau willst du damit bezwecken?
 
Ich will damit bezwecken, dass man (du kennst ja bereits meine Versuche mit OOP und dem Objekt-Proxy) eben per return ein Objekt zurück gibt. Jetzt muss da ja aber nich unbedingt noch eine Methode daraus aufgerufen werden sondern da kann ja auch gleich Schluss sein. Jetzt ist da nur blöd, dass wenn ich dann das beende ja das Objekt an sich zurück gegeben wird und das ist ja doof. Da soll z.B. NULL zurückgegeben werden.

Ich poste einfach mal meine Proxy-Klasse:
PHP:
class Proxy
{
	private $methods = array(); // Definierte Methoden
	private $data    = array(); // Gespeicherte Datensätze
	
	public function __construct()
	{
		// Wenn keine Methodennamen angegeben wurden => FATAL ERROR
		if(func_num_args() == 0)
		{
			trigger_error('Missing arguments for '.__CLASS__.'::__construct()', E_USER_ERROR);
			return FALSE;
		}
		
		// Überprüft die angegebenen Methodennamen
		foreach(func_get_args() as $method)
		{
			// Wenn der Methodenname ungültig ist oder keine Zeichenkette => FATAL ERROR
			if(!@preg_match('%^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*%', $method) || !is_string($method))
			{
				trigger_error('Invalid method name', E_USER_ERROR);
				return FALSE;
			}
		}
		
		$this->methods = func_get_args(); // Speichert die Methodennamen
		return TRUE;
	}
	
	public function __toString()
	{
		return '';
	}
	
	public function __call($strKey, $strValue)
	{
		// Wenn die aufgerufene Methode existiert (definiert in $this->methods)
		if(in_array($strKey, $this->methods))
		{
			$this->data[] = array('method'    => $strKey,    // Methodenname
								  'arguments' => $strValue); // angegebene Argumente
			return TRUE;
		}
		
		// Ansonsten: Methode wurde nicht definiert => FATAL ERROR
		trigger_error('Call to undefined method '.__CLASS__.'::'.$strKey.'()', E_USER_ERROR);
		return FALSE;
	}
	
	public function __get($strKey)
	{
		$data = $this->data;   // Datensätze in temporäre Variable speichern
		$this->data = array(); // Datensätze löschen
		return $data;          // Datensätze ausgeben
	}
}

Meine Idee war jetzt, dass ich die Methodenaufrufe protokolliere und beim Aufrufen einer "Wurzel-Methode" dann das abgearbeitet wird. Im Konstruktor wird angegeben, welche Methoden verfügbar sein sollen und per __get() kann ich dann die Daten übergeben und die werden automatisch wieder zurück gesetzt, so dass ich eine Instanz davon mehrmals benutzen kann.
 
So in etwa:
PHP:
<?php
require_once('class.proxy.php');

class test
{
	private $proxy;
	private $data = array();
	
	public function __construct()
	{
		$this->proxy = new Proxy('add', 'type', 'file');
	}
	
	public function __call($strKey, $strValue)
	{
		switch($strKey)
		{
			case 'add':
				$this->proxy->add($strValue);
				return $this->sub_add($strValue);
				break;
				
			case 'type':
				$this->proxy->type($strValue);
				return $this->sub_type($strValue);
				break;
			
			case 'file':
				$this->sub_file();
				break;
			
			default: break;
		}
	}
	
	private function sub_file()
	{
		if(count($this->proxy->data) > 0)
		{
			$data = $this->proxy->data;
			
			if($data[0]['method'] == 'file')
			{
				unset($data[0]);
				foreach($data as $method)
				{
					$key   = $method['method'];
					$value = $method['arguments'];
					$new[$key] = $value;
				}
				
				$this->data[] = $new;
			}
		}
		
		return $this;
	}
	
	private function sub_add($args)
	{
		return $this;
	}
	
	private function sub_type($args)
	{
		return NULL;
	}
	
	public function __destruct()
	{
		
	}
}

// Aufruf
$files = new test();
$files->file()->add('test.txt'); // Das ist möglich. Da aber per RETURN $this ausgeben wird, kann ich auf die Klasseninternen Variablen zugreifen
$files->file()->add('test.txt')->type('bin'); // Das ist auch möglich. Hier wird aber per RETURN Null ausgeben => kein Zugriff auf die klasseninternen Variablen
?>
 
Zuletzt bearbeitet:
Ist ja auch klar, wenn die Methode sub_type() NULL zurück gibt. Wolltest du da vielleicht ebenfalls $this zurückgeben?
 
Nein, dass wollte ich nicht. Das return NULL ist an dieser Stelle bewusst so gesetzt. Ich könnte da auch $this ausgeben, aber ich wollte es damit verdeutlichen, was ich genau will. Mein Problem ist eigentlich nur ein kleiner Schönheitsfehler, da ich nicht will das man per var_dump($class) die einzelnen Variablen einer Instanz einer Klasse ausgeben kann. Es ist also ein Problem, was generell auftreten kann - Proxy-Klasse hin oder her.
 
Ok, ich denke, ich verstehe jetzt, was du meinst. var_dump() ignoriert protected oder private.

Auszug aus var_dump:

In PHP 5 werden alle öffentlichen (public), privaten (private) und geschützten (protected) Eigenschaften eines Objekts in der Ausgabe dargestellt.

Sprich es ist nicht möglich, auf einfache Art und Weise var_dump zu überlisten.
 
Nein. Leider kann man in PHP keine Funktionen im Haupt-Namespace überladen (geht auch in keiner andern Sprache). Die einzige Möglichkeit, die ich da sehe, ist diese Funktion als unsafe zu deklarieren (evtl. über SafeMode) oder mal Stefan Esser fragen, was er von der Thematik hält und ein Plugin für suhosin zu schreiben.

Allerdings stellt sich mir die Frage, ob es den Aufwand lohnt, als es schlicht und einfach nicht zu verwenden. Es gibt bestimmt irgendwo im Web eine Alternative für var_dump(), was private und protected nicht ignoriert und nicht darstellt.
 
Zurück