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.

__sleep() y __wakeup()

public __sleep(): array
public __wakeup(): void

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();
    }
}
?>

__serialize() y __unserialize()

public __serialize(): array
public __unserialize(array $data): void

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();
    }
}
?>

__toString()

public __toString(): string

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:

Hola Mundo

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

__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:

int(5)
bool(true)

__set_state()

static __set_state(array $properties): object

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($atrue);
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().

__debugInfo()

__debugInfo(): array

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