Magische Methoden
Magische Methoden sind Methoden, die PHPs Standardverhalten überschreiben,
wenn bestimmte Aktionen mit einem Objekt durchgeführt werden.
Achtung
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().
Warnung
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();
}
}?>
public __serialize():
array
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.
Warnung
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.
Warnung
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:
__invoke(
...$values
):
mixed
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:
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)
}