Métodos mágicos

Los nombres de los métodos __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() y __debugInfo() son mágicos en las clases PHP. No se puede tener métodos con estos nombres en ninguna clase a menos que se desee la funcionalidad mágica asociada a estos.

Precaución

PHP se reserva todos los nombres de los métodos que comienzan con __ como mágicos. Se recomienda que no utilice los nombres de métodos con __ en PHP a menos que desee alguna funcionalidad mágica documentada.

__sleep() y __wakeup()

public __sleep ( void ) : array
__wakeup ( void ) : 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();
    }
}
?>

__toString()

public __toString ( void ) : 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

No se puede lanzar una excepción desde dentro un método __toString(). Hacerlo resultará en un error fatal.

Ejemplo #2 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 #3 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(), desde PHP 5.1.0.

El único parámetro de este método es un array que contiene las propiedades exportadas en la forma array('property' => value, ...).

Ejemplo #4 Uso de __set_state() (desde PHP 5.1.0)

<?php

class A
{
    public 
$var1;
    public 
$var2;

    public static function 
__set_state($an_array// A partir de PHP 5.1.0
    
{
        
$obj = new A;
        
$obj->var1 $an_array['var1'];
        
$obj->var2 $an_array['var2'];
        return 
$obj;
    }
}

$a = new A;
$a->var1 5;
$a->var2 'foo';

eval(
'$b = ' var_export($atrue) . ';'); // $b = A::__set_state(array(
                                            //    'var1' => 5,
                                            //    'var2' => 'foo',
                                            // ));
var_dump($b);

?>

El resultado del ejemplo sería:

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 fallará si __set_state() no está implementado. Esto, en particular, 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 ( void ) : 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.

Esta característica se añadió en PHP 5.6.0.

Ejemplo #5 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)
}