Métodos mágicos
Los métodos mágicos son métodos especiales que sobreescriben acciones por defecto
cuando se realizan ciertas acciones sobre un objeto.
Precaución
Todos los nombres de los métodos que comienzan con __
son reservados por PHP.
Por lo tanto, se recomienda que no utilice los nombres de métodos a menos que se sobreescriba
el comportamiento de PHP.
Los siguientes nombres de métodos se consideran mágicos:
__construct(),
__destruct(),
__call(),
__callStatic(),
__get(),
__set(),
__isset(),
__unset(),
__sleep(),
__wakeup(),
__serialize(),
__unserialize(),
__toString(),
__invoke(),
__set_state(),
__clone(), and
__debugInfo().
Advertencia
Todos los métodos mágicos, a excepción de
__construct(),
__destruct(), y
__clone(),
deben ser declarados como público
,
en caso contrario se emite un E_WARNING
.
Antes de PHP 8.0.0, no se emitía ningún diagnóstico para los métodos mágicos
__sleep(),
__wakeup(),
__serialize(),
__unserialize(), y
__set_state().
Advertencia
Si se utilizan tipo de declaraciones usados en la definición de un método mágico,
deben ser idénticas a la firma descrita en este documento.
De lo contrario, se emite un error fatal.
Antes de PHP 8.0.0, no se emitía ningún diagnóstico.
Sin embargo, __construct() y
__destruct() no debe declarar un tipo de retorno;
de lo contrario se emite un error fatal.
serialize() comprueba si la clase tiene un método con el nombre mágico
__sleep(). Si es así, el método
se ejecuta antes de cualquier serialización. Se puede limpiar el objeto
y se supone que devuelve un array con los nombres de todas las variables
de el objeto que se va a serializar.
Si el método no devuelve nada, entonces null
es serializado y un error
E_NOTICE
es emitido.
Nota:
No es posible para __sleep() devolver
nombres de propiedades privadas en las clases padres. Hacer esto resultaría un nivel de error
E_NOTICE
.
En su lugar, puede utilizar la interfaz Serializable.
El uso para el que está destinado __sleep()
consiste en confirmar datos pendientes o realizar tareas similares de limpieza.
Además, el método es útil si tiene objetos muy grandes que no necesitan guardarse por completo.
Por el contrario,
unserialize()
comprueba la presencia de un método con el nombre mágico
__wakeup(). Si está presente, este método
puede reconstruir cualquier recurso que el objeto pueda tener.
El uso para el que está destinado
__wakeup()
es restablecer las conexiones de base de datos que se puedan haber perdido
durante la serialización y realizar otras tareas de reinicialización.
Ejemplo #1 Sleep y 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();
}
}?>
public __serialize():
array
serialize() comprueba si la clase tiene una función mágica
con el nombre __serialize(). Si es así, esa función se
ejecuta antes de cualquier serialización. Debe construir y devolver un array asociativo de pares clave/valor
que representen la forma serializada del objeto. Si no se devuelve ningún array, se lanzará una clase TypeError.
Nota:
Si tanto __serialize() y __sleep()
están definidos en el mismo objeto, sólo se llamará a __serialize().
__sleep() será ignorado. Si el objeto implementa la interfaz Serializable
el método serialize()
de la interfaz será ignorado y se utilizará __serialize()
en su lugar.
El uso previsto de __serialize() es definir una representación arbitraria
del objeto que sea fácil de serializar. Los elementos de la matriz pueden corresponder a propiedades del objeto,
pero no es necesario.
Por el contrario, unserialize() comprueba la presencia
de una función con el nombre mágico
__unserialize(). Si está presente, a esta función se le pasará el array
restaurado que fue devuelto por __serialize(). Entonces puede
restaurar las propiedades del objeto desde ese array según sea apropiado.
Nota:
Si tanto __unserialize() y __wakeup()
son definidos en el mismo objeto, sólo se llamará a __unserialize().
__wakeup() será ignorado.
Nota:
Esta función está disponible a partir de PHP 7.4.0.
Ejemplo #2 Serialize y 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();
}
}?>
El método __toString() permite a una clase decidir
cómo comportarse cuando se le trata como un string. Por ejemplo, lo que
echo $obj;
mostraría.
Este método debe devolver un string, si no se emitirá un nivel de error fatal
E_RECOVERABLE_ERROR
.
Advertencia
As of PHP 8.0.0, the return value follows standard PHP type semantics,
meaning it will be coerced into a string if possible and if
strict typing
is disabled.
As of PHP 8.0.0, any class that contains a __toString()
method will also implicitly implement the Stringable interface, and will
thus pass type checks for that interface. Explicitly implementing the interface anyway is
recommended.
In PHP 7.4, the returned value must be a
string, otherwise an Error is thrown.
Prior to PHP 7.4.0, the returned value must be a
string, otherwise a fatal E_RECOVERABLE_ERROR
is emitted.
Advertencia
No se puede lanzar una excepción desde dentro un método
__toString().
El método antes de PHP 7.4.0. Si lo hace, se producirá un error fatal.
Ejemplo #3 Ejemplo simple
<?php
// Declarar una clase simple
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new TestClass('Hola Mundo');
echo $class;
?>
El resultado del ejemplo sería:
Antes de PHP 5.2.0 el método
__toString()
se llama sólo cuando se combina directamente con
echo
o
print. Desde PHP 5.2.0, se le llama en cualquier contexto de string (e.j. en
printf()
con el modificador
%s
) pero no en el contexto de otros tipos (e.j. con el modificador
%d
). Desde PHP 5.2.0, la conversión de los objetos sin el método
__toString()
a string podría causar
E_RECOVERABLE_ERROR
.
__invoke(
$...
= ?):
mixed
El método
__invoke()
es llamado cuando un script intenta llamar a un objeto como si fuera una función.
Nota:
Esta característica está disponible desde PHP 5.3.0.
Ejemplo #4 Uso de
__invoke()
<?php
class CallableClass
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
El resultado del ejemplo sería:
Este método static es llamado
para las clases exportadas por var_export().
El único parámetro de este método es un array que contiene las propiedades exportadas
en la forma ['property' => value, ...]
.
Ejemplo #5 Uso de __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);
?>
El resultado del ejemplo sería:
string(60) "A::__set_state(array(
'var1' => 5,
'var2' => 'foo',
))"
object(A)#2 (2) {
["var1"]=>
int(5)
["var2"]=>
string(3) "foo"
}
Nota:
Al exportar un objeto, var_export() no comprueba si
__set_state() está implementado por la clase del objeto,
por lo que la reimportación de tales objetos dará lugar a una excepción Error,
si __set_state() no está implementado. En particular, esto afecta a algunas
clases internas.
Es responsabilidad del programador verificar que solamente se vayan a reimportar
los objetos cuya clase implemente __set_state().
Este método es invocado por var_dump() al volcar un
objeto para obtener las propiedades que deberían mostrarse. Si el método no está
definido sobre un objeto, se mostrarán todas las propiedades públicas
protegidas y privadas.
Ejemplo #6 Utilizar __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));
?>
El resultado del ejemplo sería:
object(C)#1 (1) {
["propSquared"]=>
int(1764)
}