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)
}