Les méthodes magiques sont des méthodes spéciales qui écrasent l'action par défaut de PHP quand certaines actions sont réalisées sur un objet.
Toutes les méthodes commençant par __
sont réservé par PHP.
Ainsi, il n'est pas recommandé d'utiliser un tel nom de méthode sauf lors
de l'écrasage du comportement de PHP.
Les méthodes suivantes sont considérées magiques : __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state() __clone(), et __debugInfo().
Toutes les méthodes magiques, à l'exception de
__construct(),
__destruct(), et
__clone(),
doivent être déclaré en tant que public
,
sinon une E_WARNING
est émise.
Antérieur à PHP 8.0.0, aucun diagnostic n'était émis pour les méthodes magiques
__sleep(),
__wakeup(),
__serialize(),
__unserialize(), et
__set_state().
Si des déclarations de types sont utilisé dans la définition d'une méthode magique, elles doivent être identique à la signature décrit dans ce document. Sinon, une erreur fatale est émise. Antérieur à PHP 8.0.0, aucun diagnostic n'était émis. Cependant, __construct() et __destruct() ne doivent pas déclarer un type de retour ; sinon une erreur fatale est émise.
serialize() vérifie si la classe a une méthode avec le
nom magique __sleep().
Si c'est le cas, cette méthode sera exécutée avant toute linéarisation. Elle peut
nettoyer l'objet, et elle est supposée retourner un tableau avec les noms de toutes
les variables de l'objet qui doivent être linéarisées.
Si la méthode ne retourne rien, alors null
sera linéarisé, et une alerte de type
E_NOTICE
sera émise.
Note:
Il n'est pas possible pour __sleep() de retourner des noms de propriétés privées des classes parentes. Le faire résultera en une erreur de niveau
E_NOTICE
. Utilisez __serialize() à la place.
Le but avoué de __sleep() est de valider des données en attente ou d'effectuer des opérations de nettoyage. De plus, cette fonction est utile si un objet très large n'a pas besoin d'être sauvegardés dans sa totalité.
Réciproquement, la fonction unserialize() vérifie la présence d'une méthode dont le nom est le nom magique __wakeup(). Si elle est présente, cette fonction peut reconstruire toute ressource que l'objet pourrait posséder.
Le but avoué de __wakeup() est de rétablir toute connexion de base de données qui aurait été perdue durant la linéarisation et d'effectuer des tâches de réinitialisation.
Exemple #1 Utilisation de sleep() et wakeup()
<?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();
}
}
?>
$data
): voidserialize() vérifie si la classe a une méthode avec le nom magique __serialize(). Si c'est le cas, cette méthode sera exécutée avant toute linéarisation. Elle doit construire et retourner un tableau associatif de paire clé/valeur qui représente la forme linéarisée de l'objet. Si aucun tableau n'est retournée une TypeError sera lancée.
Note:
Si __serialize() et __sleep() sont tout les deux définie dans le même objet, alors seulement __serialize() sera appelé. __sleep() sera ignoré. Si l'objet implémente l'interface Serializable, la méthode
serialize()
de l'interface sera ignorée et __serialize() sera utilisé à la place.
L'utilisation prévue de __serialize() est de définir une représentation arbitraire de l'objet pour le linéariser facilement. Les éléments du tableau peuvent correspondre aux propriétés de l'objet mais ceci n'est pas requis.
inversement, unserialize() vérifie la présence d'une fonction avec le nom magique __unserialize(). Si présent, cette fonction sera passé le tableau restauré qui a été retournée depuis __serialize(). Il peut alors restaurer les propriétés de l'objet depuis ce tableau comme approprié.
Note:
Si __unserialize() et __wakeup() sont tout les deux définie dans le même objet, alors seulement __unserialize() sera appelée. __wakeup() sera ignorée.
Note:
Cette fonctionnalité est disponible à partir de PHP 7.4.0.
Exemple #2 Serialize et 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();
}
}?>
La méthode __toString() détermine comment l'objet
doit réagir lorsqu'il est traité comme une chaîne de caractères.
Par exemple, ce que echo $obj;
affichera.
À partir de PHP 8.0.0, la valeur de retour suit les sémantiques standard de PHP, signifiant que la valeur sera convertie en une string si possible et si le typage stricte est désactivé.
À partir de PHP 8.0.0, toute classe qui contient une méthode __toString() implémente aussi implicitement l'interface Stringable, et passera donc les vérifications de types pour cette interface. Implémenter quand même explicitement l'interface est recommandé.
En PHP 7.4, la valeur de retour doit être une string, sinon une Error est lancé.
Antérieur à PHP 7.4.0, la valeur de retour doit
être une string, sinon une E_RECOVERABLE_ERROR
fatale est émise.
Il était impossible de lancer une exception depuis la méthode __toString() antérieur à PHP 7.4.0. Cela entraînera une erreur fatale.
Exemple #3 Exemple simple
<?php
// Déclaration d'une classe simple
class ClasseTest
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new ClasseTest('Bonjour');
echo $class;
?>
L'exemple ci-dessus va afficher :
Bonjour
La méthode __invoke() est appelée lorsqu'un script tente d'appeler un objet comme une fonction.
Exemple #4 Exemple avec __invoke()
<?php
class CallableClass
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
L'exemple ci-dessus va afficher :
int(5) bool(true)
Exemple #5 Exemple avec __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']
];
// trier les clients par prénom
usort($customers, new Sort('first_name'));
print_r($customers);
// trier les clients par nom de famille
usort($customers, new Sort('last_name'));
print_r($customers);
?>
L'exemple ci-dessus va afficher :
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 ) )
$properties
): objectCette méthode statique est appelée pour les classes exportées par la fonction var_export().
Le seul paramètre de cette méthode est un tableau contenant les propriétés
exportées sous la forme ['property' => value, ...]
.
Exemple #6 Utilisation de __set_state()
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);
?>
L'exemple ci-dessus va afficher :
string(60) "A::__set_state(array( 'var1' => 5, 'var2' => 'foo', ))" object(A)#2 (2) { ["var1"]=> int(5) ["var2"]=> string(3) "foo" }
Note: Lors de l'exportation d'un objet, var_export() ne vérifie pas si __set_state() est implémenté par la classe de l'objet, ainsi la réimportation d'objets résultera en une exception Error, si __set_state() n'est pas implémenté. En particulier, cela affecte certaines classes internes. Il est de la responsabilité du programmeur de vérifier que seuls les objets dont la classe implémente __set_state() seront ré-importés.
Cette méthode est appelée par var_dump() lors du traitement d'un objet pour récupérer les propriétés qui doivent être affichées. Si la méthode n'est pas définie dans un objet, alors toutes les propriétés publiques, protégées et privées seront affichées.
Exemple #7 Utilisation de __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));
?>
L'exemple ci-dessus va afficher :
object(C)#1 (1) { ["propSquared"]=> int(1764) }