Magische Methoden sind Methoden, die PHPs Standardverhalten überschreiben, wenn bestimmte Aktionen mit einem Objekt durchgeführt werden.
Alle Methodennamen, die mit __
beginnen, sind durch
PHP reserviert. Es wird daher nicht empfohlen solche Methodennamen zu
verwenden, außer wenn das Verhalten von PHP überschrieben werden soll.
Die folgenden Methodennamen werden als magisch betrachtet: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone() und __debugInfo().
Mit Ausnahme von
__construct(),
__destruct() und
__clone() müssen
alle magischen Methoden als public
deklariert werden,
andernfalls wird eine E_WARNING
ausgegeben.
Vor PHP 8.0.0 wurde für die magischen Methoden
__sleep(),
__wakeup(),
__serialize(),
__unserialize() und
__set_state() keine Diagnose
ausgegeben.
Falls Typdeklarationen in der Definition der magischen Methoden angegeben werden, müssen diese identisch zu den Signaturen sein, die in diesem Dokument beschrieben werden, andernfalls wird ein fataler Fehler hervorgerufen. Vor PHP 8.0.0 wurde keine Diagnose ausgegeben. Allerdings dürfen __construct() und __destruct() keinen Rückgabetyp deklarieren, sonst wird ein fataler Fehler ausgegeben.
serialize() prüft, ob die Klasse eine Funktion mit dem
magischen Namen __sleep() besitzt.
Wenn dem so ist, wird die Funktion vor jeder Serialisierung ausgeführt.
Sie kann das Objekt aufräumen und es wird von ihr erwartet, dass sie ein
Array mit den Namen aller Variablen zurückgibt, die serialisiert werden
sollen. Wenn die Methode nichts zurückgibt, wird null
serialisiert und
eine E_NOTICE
ausgegeben.
Hinweis:
__sleep() kann keine Namen von privaten Eigenschaften in Elternklassen zurückgeben. Dies würde zu einem Fehler der Stufe
E_NOTICE
führen. Stattdessen sollte das Serializable-Interface verwendet werden.
Hinweis:
Seit PHP 8.0.0 erzeugt die Rückgabe eines Wertes von __sleep(), der kein Array ist, eine Warnung; vorher führte dies zu einem Hinweis.
Der Zweck von von __sleep() ist, nicht gespeicherte Daten zu sichern oder ähnliche Aufräumarbeiten zu erledigen. Die Funktion ist ebenfalls nützlich, wenn ein sehr großes Objekt nicht komplett gespeichert werden muss.
Umgekehrt überprüft unserialize(), ob eine Funktion mit dem magischen Namen __wakeup() vorhanden ist. Falls vorhanden, kann diese Funktion alle Ressourcen, die das Objekt möglicherweise hat, wiederherstellen.
Der Zweck von __wakeup() ist es, alle Datenbankverbindungen, die bei der Serialisierung verlorengegangen sind, wiederherzustellen und andere Aufgaben der erneuten Initialisierung durchzuführen.
Beispiel #1 Sleep- und Wakeup-Beispiel
<?php
class Connection
{
protected $link;
private $dsn, $username, $password;
public function __construct($dsn, $username, $password)
{
$this->dsn = $dsn;
$this->username = $username;
$this->password = $password;
$this->connect();
}
private function connect()
{
$this->link = new PDO($this->dsn, $this->username, $this->password);
}
public function __sleep()
{
return array('dsn', 'username', 'password');
}
public function __wakeup()
{
$this->connect();
}
}?>
serialize() prüft, ob die Klasse eine Funktion mit dem magischen Namen __serialize() besitzt. Wenn dem so ist, wird die Funktion vor jeder Serialisierung ausgeführt. Sie muss ein assoziatives Array von Schlüssel/Wert-Paaren erzeugen und zurückgeben, die die serialisierte Form des Objekts darstellen. Wird kein Array zurückgegeben, wird ein TypeError geworfen.
Hinweis:
Sind sowohl __serialize() als auch __sleep() im selben Objekt definiert, wird nur __serialize() aufgerufen. __sleep() wird ignoriert. Implementiert das Objekt das Serializable-Interface, wird die
serialize()
-Methode des Interfaces ignoriert und stattdessen __serialize() verwendet.
Der Zweck von __serialize() ist, eine für die Serialisierung geeignete beliebige Darstellung eines Objekts zu definieren. Die Elemente des Arrays können den Eigenschaften des Objekts entsprechen, aber das ist nicht erforderlich.
Umgekehrt überprüft unserialize(), ob eine Funktion mit dem magischen Namen __unserialize() vorhanden ist. Falls vorhanden, wird dieser Funktion das wiederhergestellte Array übergeben, das von __serialize() zurückgegeben wurde. Sie kann dann gegebenenfalls die Eigenschaften des Objekts aus diesem Array wiederherstellen.
Hinweis:
Sind sowohl __unserialize() als auch __wakeup() im selben Objekt definiert, wird nur __unserialize() aufgerufen. __wakeup() wird ignoriert.
Hinweis:
Dieses Feature ist seit PHP 7.4.0 verfügbar.
Beispiel #2 Serialize und unserialize
<?php
class Connection
{
protected $link;
private $dsn, $username, $password;
public function __construct($dsn, $username, $password)
{
$this->dsn = $dsn;
$this->username = $username;
$this->password = $password;
$this->connect();
}
private function connect()
{
$this->link = new PDO($this->dsn, $this->username, $this->password);
}
public function __serialize(): array
{
return [
'dsn' => $this->dsn,
'user' => $this->username,
'pass' => $this->password,
];
}
public function __unserialize(array $data): void
{
$this->dsn = $data['dsn'];
$this->username = $data['user'];
$this->password = $data['pass'];
$this->connect();
}
}?>
Mit der Methode __toString() kann
eine Klasse entscheiden, wie sie reagieren soll, wenn sie wie eine
Zeichenkette behandelt wird. Die beeinflusst beispielsweise, was
echo $obj;
ausgeben wird.
Seit PHP 8.0.0 unterliegt der Rückgabewert dieser Methode der üblichen PHP-Semantik für Typen. Das heißt, er bei deaktivierter strikter Typisierung nach Möglichkeit in einen String umgewandelt.
Wenn die Strikte Typisierung aktiviert ist, wird ein Stringable-Objekt von einer string-Typdeklaration nicht akzeptiert. Wenn ein solches Verhalten erwünscht ist, muss die Typdeklaration Stringable und string mittels Union-Typ akzeptieren.
Seit PHP 8.0.0 implementiert jede Klasse, die eine __toString()-Methode enthält, implizit auch das Interface Stringable und erfüllt daher auch Typprüfungen auf dieses Interface. Es wird dennoch empfohlen, dieses Interface explizit zu implementieren.
In PHP 7.4 muss der Rückgabewert ein Wert vom Typ string sein, andernfalls wird ein Error geworfen.
Vor PHP 7.4.0 muss der Rückgabewert ein Wert vom Typ
string sein, ansonsten wird ein Fehler der Stufe
E_RECOVERABLE_ERROR
hervorgerufen.
Es war vor PHP 7.4.0 nicht möglich eine Exception aus einer __toString()-Methode zu werfen. Dies resultierte in einem fatalen Fehler.
Beispiel #3 Einfaches Beispiel
<?php
// Deklariere eine einfache Klasse
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new TestClass('Hallo');
echo $class;
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
Hallo
Die Methode __invoke() wird aufgerufen, wenn ein Skript versucht, ein Objekt als Funktion aufzurufen.
Beispiel #4 Nutzung von __invoke()
<?php
class CallableClass
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
int(5) bool(true)
Beispiel #5 Nutzung von __invoke()
<?php
class Sort
{
private $key;
public function __construct(string $key)
{
$this->key = $key;
}
public function __invoke(array $a, array $b): int
{
return $a[$this->key] <=> $b[$this->key];
}
}
$customers = [
['id' => 1, 'first_name' => 'John', 'last_name' => 'Do'],
['id' => 3, 'first_name' => 'Alice', 'last_name' => 'Gustav'],
['id' => 2, 'first_name' => 'Bob', 'last_name' => 'Filipe']
];
// Kunden nach Vornamen sortieren
usort($customers, new Sort('first_name'));
print_r($customers);
// Kunden nach Nachnamen sortieren
usort($customers, new Sort('last_name'));
print_r($customers);
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
Array ( [0] => Array ( [id] => 3 [first_name] => Alice [last_name] => Gustav ) [1] => Array ( [id] => 2 [first_name] => Bob [last_name] => Filipe ) [2] => Array ( [id] => 1 [first_name] => John [last_name] => Do ) ) Array ( [0] => Array ( [id] => 1 [first_name] => John [last_name] => Do ) [1] => Array ( [id] => 2 [first_name] => Bob [last_name] => Filipe ) [2] => Array ( [id] => 3 [first_name] => Alice [last_name] => Gustav ) )
Diese statische Methode wird für Klassen aufgerufen, die mittels var_export() exportiert werden.
Der einzige Parameter dieser Methode ist ein Array, welches aus
exportierten Eigenschaften der Form ['Eigenschaft' => Wert,
...]
besteht.
Beispiel #6 Verwendung von __set_state()
<?php
class A
{
public $var1;
public $var2;
public static function __set_state($an_array)
{
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
$b = var_export($a, true);
var_dump($b);
eval('$c = ' . $b . ';');
var_dump($c);
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
string(60) "A::__set_state(array( 'var1' => 5, 'var2' => 'foo', ))" object(A)#2 (2) { ["var1"]=> int(5) ["var2"]=> string(3) "foo" }
Hinweis: Wenn ein Objekt exportiert wird, überprüft var_export() nicht, ob __set_state() von der Objektklasse implementiert wird, sodass der erneute Import von Objekten zu einer Error-Exception führt, falls __set_state() nicht implementiert ist. Die betrifft insbesondere einige interne Klassen. Es liegt im Aufgabenbereich des Programmiers, sicherzustellen, dass nur Objekte wieder re-importiert werden, welche auch __set_state() implementieren.
Diese Methode wird von var_dump() aufgerufen, wenn ein Objekt ausgegeben wird, um die Eigenschaften auszulesen die gezeigt werden sollen. Wenn diese Methode in einem Objekt nicht definiert ist, so werden alle Eigenschaften angezeigt, die public, protected oder private sind.
Beispiel #7 Verwendung von __debugInfo()
<?php
class C {
private $prop;
public function __construct($val) {
$this->prop = $val;
}
public function __debugInfo() {
return [
'propSquared' => $this->prop ** 2,
];
}
}
var_dump(new C(42));
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
object(C)#1 (1) { ["propSquared"]=> int(1764) }