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, wenn man nicht PHPs Verhalten überschreiben möchte.
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 Diagnostik ausgegeben. Allerdings
dürfen __construct() und
__destruct() keinen Rückgabetyp
deklarieren, sonst wird ein fataler Fehler ausgegeben.
public __sleep(): array
public __wakeup(): void
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ück liefert, die serialisiert werden sollen. Wenn die
Methode nichts zurück gibt, so wird null
serialisiert und eine
E_NOTICE
geworfen.
Hinweis:
__sleep() kann nicht Namen von privaten
Eigenschaften von Elternklassen zurückgeben. In diesem Fall wird eine
E_NOTICE
geworfen. Stattdessen sollte das
Serializable-Interface verwendet werden.
Die beabsichtigte Verwendung 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() die Anwesenheit einer
Funktion mit dem magischen Namen __wakeup().
Falls vorhanden, kann diese Funktion alle Ressourcen, die das Objekt haben könnte,
wiederherstellen.
Der beabsichtigte Zweck von __wakeup() ist es,
alle Datenbankverbindungen wiederherzustellen, die während der Serialisierung
verloren gegangen sein könnten, oder auch andere Aufgaben zur erneuten Initialisierung.
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
public __unserialize(array $data
): void
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 Interface ignoriert und
__serialize() statt dessen verwendet.
Die beabsichtigte Verwendung von __serialize() ist,
eine serialisierungsfreundlich beliebige Darstellung eines Objekts zu definieren.
Elemente des Arrays dürfen Eigenschaften entsprechen, aber das ist nicht erforderlich.
Umgekehrt überprüft unserialize() die Anwesenheit einer Funktion mit dem magischen
Namen __unserialize(). Falls vorhanden, wird dieser Funktion
das wiederhergestellte Array übergeben, das von __serialize()
zurückgegeben wurde. Sie kann dann dementsprechend 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();
}
}?>
public __toString(): string
Die __toString() Methode erlaubt
einer Klasse zu entscheiden, wie sie reagieren soll, wenn sie in eine Zeichenkette
umgewandelt wird. Die beeinflusst beispielsweise, was echo $obj;
ausgeben wird.
Warnung
Seit PHP 8.0.0 unterliegt der Rückgabewert dieser Methode der üblichen PHP Typsemantik.
Das heißt, er wird wenn möglich in einen String umgewandelt, wenn
strikte Typisierung
deaktiviert ist.
Seit PHP 8.0.0 implementiert jede Klasse die eine
__toString()-Methode enthält implizit auch das
Interface Stringable und erfüllen 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 String
sein, andernfalls wird ein Error geworfen.
Vor PHP 7.4.0 muss der Rückgabewert ein 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(
$...
= ?):
mixed
Die __invoke()-Methode wird aufgerufen,
wenn ein Skript versucht, ein Objekt als Funktion aufzurufen.
Beispiel #4 Nutzung von __invoke()
<?php
class CallableClass
{
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
)
)
static __set_state(array $properties
): object
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 array('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 im Besonderen einige
interne Klassen.
Es liegt im Aufgabenbereich des Programmiers sicherzustellen, dass nur Objekte
wieder re-importiert werden, welche auch __set_state() implementieren.
__debugInfo(): array
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 die public, protected oder private sind
angezeigt.
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)
}