Surcharge magique

La surcharge magique en PHP permet de "créer" dynamiquement des propriétés et des méthodes. Ces entités dynamiques sont traitées via des méthodes magiques établies que l'on peut positionner dans une classe pour divers types d'actions.

Les méthodes magiques de surcharge sont appelées lors de l'interaction avec des propriétés ou des méthodes qui n'ont pas été déclarées ou ne sont pas visibles dans le contexte courant. Le reste de cette section utilise les termes de "propriétés inaccessibles" et de "méthodes inaccessibles" pour se référer à cette combinaison de déclaration et de visibilité.

Toutes les méthodes magiques de surcharge doivent être définies comme public.

Note:

Aucun des arguments de ces méthodes magiques ne peut être passé par référence.

Note:

L'interprétation PHP de la "surcharge" est différente de celle de la plupart des langages orientés objet. La surcharge, habituellement, fournit la possibilité d'avoir plusieurs méthodes portant le même nom mais avec une quantité et des types différents d'arguments.

Historique

Version Description
5.3.0 Ajout de __callStatic(). Ajout d'un avertissement pour forcer la visibilité public et la déclaration non static.
5.1.0 Ajout de __isset() et de __unset().

Surcharge de propriétés

public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )

__set() est sollicitée lors de l'écriture de données vers des propriétés inaccessibles.

__get() est appelée pour lire des données depuis des propriétés inaccessibles.

__isset() est sollicitée lorsque isset() ou la fonction empty() sont appelées sur des propriétés inaccessibles.

__unset() est invoquée lorsque unset() est appelée sur des propriétés inaccessibles.

L'argument $name est le nom de la propriété avec laquelle on interagit. L'argument $value de la méthode __set() spécifie la valeur à laquelle la propriété $name devrait être définie.

La surcharge de propriétés ne fonctionne que dans les contextes objets. Ces méthodes magiques ne seront pas lancées en contexte statique. Par conséquent, ces méthodes ne devraient pas être déclarées comme statiques. Depuis PHP 5.3.0, un avertissement est levée si une des méthodes magiques est déclarée comme statique.

Note:

La valeur retournée par __set() est ignorée en raison de la façon dont PHP traite l'opérateur d'affectation. De la même façon, __get() n'est jamais appelée lors d'un enchaînement d'assignements, comme ceci :

 $a = $obj->b = 8; 

Note:

Il n'est pas possible d'utiliser les attributs surchargés dans d'autres structures de langages que isset(). Ceci signifie que si empty() est appelée avec un attribut surchargé, la méthode de surcharge n'est pas invoquée.

Pour contourner cette limitation, l'attribut surchargé doit être copié dans une variable locale du contexte courant, elle-même passée à empty().

Exemple #1 Exemple de surcharge de propriétés avec les méthodes __get(), __set(), __isset() et __unset()

<?php
class PropertyTest
{
	/**  Variable pour les données surchargées.  */
	private $data = array();

	/**  La surcharge n'est pas utilisée sur les propriétés déclarées.  */
	public $declared = 1;

	/**  La surcharge n'est lancée que lorsque l'on accède à cette propriété depuis l'extérieur de la classe.  */
	private $hidden = 2;

	public function __set($name, $value)
	{
		echo "Définition de '$name' à la valeur '$value'\n";
		$this->data[$name] = $value;
	}

	public function __get($name)
	{
		echo "Récupération de '$name'\n";
		if (array_key_exists($name, $this->data)) {
			return $this->data[$name];
		}

		$trace = debug_backtrace();
		trigger_error(
			'Propriété non-définie via __get() : ' . $name .
			' dans ' . $trace[0]['file'] .
			' à la ligne ' . $trace[0]['line'],
			E_USER_NOTICE);
		return null;
	}

	/**  Depuis PHP 5.1.0  */
	public function __isset($name)
	{
		echo "Est-ce que '$name' est défini ?\n";
		return isset($this->data[$name]);
	}

	/**  Depuis PHP 5.1.0  */
	public function __unset($name)
	{
		echo "Effacement de '$name'\n";
		unset($this->data[$name]);
	}

	/**  Ce n'est pas une méthode magique, nécessaire ici que pour l'exemple.  */
	public function getHidden()
	{
		return $this->hidden;
	}
}


echo "<pre>\n";

$obj = new PropertyTest;

$obj->a = 1;
echo $obj->a . "\n\n";

var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";

echo $obj->declared . "\n\n";

echo "Manipulons maintenant la propriété privée nommée 'hidden' :\n";
echo "'hidden' est visible depuis la classe, donc __get() n'est pas utilisée...\n";
echo $obj->getHidden() . "\n";
echo "'hidden' n'est pas visible en dehors de la classe, donc __get() est utilisée...\n";
echo $obj->hidden . "\n";
?>
<?php
class MethodTest
{
	public function __call($name, $arguments)
	{
		// Note : la valeur de $name est sensible à la casse.
		echo "Appel de la méthode '$name' "
			 . implode(', ', $arguments). "\n";
	}

	/**  Depuis PHP 5.3.0  */
	public static function __callStatic($name, $arguments)
	{
		// Note : la valeur de $name est sensible à la casse.
		echo "Appel de la méthode statique '$name' "
			 . implode(', ', $arguments). "\n";
	}
}

$obj = new MethodTest;
$obj->runTest('dans un contexte objet');

MethodTest::runTest('dans un contexte static');  // Depuis PHP 5.3.0
?>

L'exemple ci-dessus va afficher :

Appel de la méthode 'runTest' dans un contexte objet
Appel de la méthode statique 'runTest' dans un contexte static
LoadingChargement en cours