2

Todo sobre: Métodos Mágicos en PHP!!!

Métodos Mágicos

Se denominan métodos mágicos a aquellos métodos de un objeto que son llamados sin que nosotros lo hagamos explícitamente. Funcionan como “interceptores “que se auto invocan cuando se dispara una condición o evento; es decir, sin necesidad de especificar el nombre del método en concreto. Estas particularidades de los métodos mágicos nos permiten saber cuándo un programador está interactuando con un objeto; permitiéndonos realizar acciones antes o después de esto.

Métodos mágicos más destacados:

__construct
__destruct()
__get()
__set()
__call()
__callStatic()
__clone()
__isset()
__unset()
__toString ()
__sleep ()
__wakeUp ()
__invoke ()

**__construct: **
Evento que lo dispara: este método es llamado al crear una nueva instancia del objeto.

Finalidad: Permite inyectar parámetros para construir (inicializar) el objeto.

Sintaxis:
`class Job
{
/* Propiedades */
public $titulo;
public $descripcion;
public $visible = true;
public $meses;

/* Constructor */

public function __construct($contTitulo,$contDescripcion) 
{
    $this->titulo = $contTitulo;
    $this->descripcion = $contDescripcion;                
}

}
`
Consideraciones:
En el ejemplo de arriba configuramos el constructor de la clase Job para que durante la creación de una nueva instancia de la clase se inyecten automáticamente dos parámetros que serán los valores de las propiedades título y descripción respectivamente. Es decir un objeto de tipo Job se creara con dos de sus 4 parámetros definidos al momento de su creación.
Es por lejos el método mágico más utilizado del lenguaje.

__destruct()
Evento que lo dispara: este método es llamado cuando no existen referencias a un objeto determinado, o en cualquier otra circunstancia de finalización.

Finalidad: Permite ejecutar una acción antes de la extinción del objeto.

Sintaxis:
`public function __destruct(){

/* Cierra la conexión a la base */
$this->con->destruir();

}`

_Consideraciones: _
El caso de uso más común es el cierre de las conexiones de base de datos.

__get()
Evento que lo dispara: este método es llamado cuando se trata de acceder al valor de una propiedad private o protected independientemente de su existencia o no.

Finalidad: Permite consultar el valor de una propiedad private o protected o determinar su existencia.

Sintaxis:
`class Job
{
/* Propiedades */
private $titulo;
public $descripcion;
public $visible = true;
public $meses;
private $tutor = ‘juan’;

public function __get($propiedad)
{
return $this->$propiedad;

	}

}

$job1 = new Job();

var_dump($job1->tutor);
/* Devuelve: string(4) “juan”, aunque la propiedad este seteada como privada */
`
Consideraciones:
Como vemos en el ejemplo el método __get recibe un único parámetro que es la propiedad a la que se quiere acceder.
Entonces, definir __get nos permitirá acceder desde fuera del objeto y “de forma genérica” a cualquier propiedad del mismo, independientemente de que esta esté declara como private o protected. Por esto mismo debemos ser muy cuidadosos en su implementación ya que, para el caso, es como si hubiéramos declarado todos los atributos como públicos, perdiendo así las ventajas de la ocultación o encapsulamiento. Por lo general este método es reemplazado por los llamados métodos getters, que nos permiten “individualizar” los accesos a un atributo. Es decir, la buena práctica seria definir mediante getters los accesos a los atributos del objeto evitando declarar el método __get que definiría el acceso general a todos los atributos privadas o no declaradas.

Ejemplo de getter:
`class Job {
private $title;
public $description;
public $visible;
public $months;

/* Metodo para mostrar titulo */
public function obtenerTitulo () {
    return $this -> title;
}    

}
`
__set()
Evento que lo dispara: este método es llamado cuando se trata de definir o modificar el valor de un atributo private o protected independientemente de su existencia o no.

Finalidad: Permite definir o modificar el valor de un atributo private o protected o dependiendo de su existencia o no.

Sintaxis:
`class Job
{
/* Propiedades */
private $titulo;
public $descripcion;
public $visible = true;
public $meses;
private $tutor;

 public function __set($propiedad,$valor)
{
    return $this->$propiedad = $valor;
}

}

$job1 = new Job();

$job1->tutor = ‘Juan’;

var_dump($job1->tutor);
/* Devuelve: string(4) “juan” */
`
Consideraciones:
Como vemos en el ejemplo el método __set recibe dos parámetros que son: el nombre del atributo que se quiere definir/modificar, y el valor que se le asignara al mismo.
Entonces, definir __set nos permitirá configurar desde fuera del objeto y “de forma genérica” a cualquier atributo del mismo, independientemente de que este esté declara como private o protected. Al igual que el método __get debemos ser muy cuidadosos en su implementación ya que, para el caso, es como si hubiéramos declarado todos los atributos como públicos, y entonces podremos setear su valor desde fuera del objeto. Para este caso también se recomienda utilizar en su lugar el método setter que nos permitirán “individualizar” las asignaciones o modificaciones a un atributo.

_ Ejemplo de setter:_
`class Job {
private $title;
public $description;
public $visible;
public $months;

/* Metodo para setear titulo */
public function setearTitulo ($titulo) {
    return $this -> title = $titulo;
}

}`

__call
Evento que lo dispara: este método es llamado cuando se trata de llamar a un método que no existe o a un método private o protected desde el contexto del objeto.

Finalidad: Permite realizar una acción al llamar a un método no accesible o inexistente del objeto.

Sintaxis:
`class Job {
private $title;
public $description;
public $visible;
public $months;

/* Metodo para setear titulo */

public function __call($metodo,$argumentos) {
$argumentos = implode(’, ', $argumentos);
echo “fallo al llamar al método $metodo() con los argumentos $argumentos”;
}
}`

Consideraciones:
Como podemos visualizar en el ejemplo el método __call recibe dos parámetros, uno es el nombre del método al que se está intenta invocar, y el otro el/los parámetros que le hemos pasado.
En el ejemplo citado estamos programando una respuesta automática cada vez que se invoque un método no definido.
Una aplicación más práctica del método _call sería crear ‘setter’ y ‘getters’ dinámicos y de esta manera evitar recurrir a los “polémicos” métodos __get y __set de php:

Para que el siguiente código funcione sin errores debemos respetar las convenciones setNombreAtributo y getNombreAtributodurante la definición de los métodos

`public function __call($metodo, $argumentos = null)
{ // si igualamos los argumentos a null permitimos este tipo de valores en los argumentos
/* convertimos el nombre del metodos a minusculas /
$metodo = strtolower($metodo);
/
extraemos los primeros 3 caractres del nombre del metodo y lo guardamos en la variable prefijo /
$prefijo = substr($metodo, 0, 3);
/
extraemos el nombre del atributo, es decir todo lo que le siga a las 3 primeras letras (set o get) y lo guardamos en la variable atributo */
$atributo = substr($metodo, 3);

    /* Revisamos si el prefio es iguala a set y hay un unico argumento  */
    if ($prefijo == 'set' && count($argumentos) == 1) {

        /* Si existe el atributo en la clase */
        if (property_exists(__CLASS__, $atributo)) {

            /* Creo la variable valor, que contendra el valor del atributo y le asignos el valor del argumento */
            $valor = $argumentos[0];

            /* Asignos la variable valor al atributo */
            $this->$atributo = $valor;
        
        /* Si no existe el atributo en la lcase */
        } else {

            /* Muestro mensaje de error */
            echo "No existe el atributo $atributo.";
        }

        /* Si el prefijo es igual a get */
    } elseif ($prefijo == 'get') {

        /* Si existe el atributo en la clase */
        if (property_exists(__CLASS__, $atributo)) { 
            
            /* Muestro el valor del atributo */
            return $this->$atributo;  
          }
          
        /* Si no existe el atributo en la clase devuelvo null */  
        return NULL;  

        /* Si el prefijo no se corresponde con ninguno de los dos */
    } else {
        echo 'Método no definido <br/>';
    }

   
} 

`

__callStatic()
Evento que lo dispara: este método es llamado cuando se trata de llamar a un método estático no accesible (que no existe o que está declarado como private o protected).
Los métodos estáticos están anclados a la clase, no a la instancia de la clase

Finalidad: Permite realizar una acción al llamar a un método estático no accesible del objeto.

Sintaxis:
`class Job {
private $title;
public $description;
public $visible;
public $months;

public static function __callStatic($metodo, $argumentos) {

    echo "fallo al llamar al método estatico $metodo() con los argumentos $argumentos";  

  }

}
`

__clone()
Evento que lo dispara: este método es llamado luego de la clonación de un objeto con la palabra reservada clone

Finalidad: Permite realizar acciones sobre el nuevo objeto clonado.

Sintaxis:
`class Producto {

private $idProducto;  
private $nombre;  
private $categoria;

 function __construct($idProducto,$nombre, $categoria) {  

  $this->idProducto = $idProducto;  
  $this->nombre = $nombre;  
  $this->categoria = $categoria;  

}  

public function __call($metodo, $argumentos = null)
{ …
}

	function __clone() {  
  $this->idProducto = ++$this->idProducto;   
	}  

}

$producto1 = new Producto(1, “Manteca”, “Lacteos”);
$copia_producto1 = clone $producto1;

$copia_producto1->getId();

`
__isset()
Evento que lo dispara: la función isset() de PHP determina la existencia o no de una variable, pero si quisiéramos utilizar la función isset para saber si existe un atributo no definido o inexistente de un objeto debemos definir primero el método mágico __isset. Este método es llamado automáticamente cuando se invoca la función isset() sobre un atributo inaccesible o no definido de un objeto.

Finalidad: Permite programar acciones con posterioridad a la invocación de la función isset().

Sintaxis:
`class Job
{
/* Propiedades */
private $titulo;
public $descripcion;
public $visible = true;
public $meses;
private $tutor;

/* Constructor */

public function __construct($contTitulo, $contDescripcion)
{
    $this->agregarTitulo($contTitulo);
    $this->descripcion = $contDescripcion;
}

function __isset($atributo) {

 		return isset($this->$atributo);
   
}  

} /* Fin de la clase */

isset($job1->años); // Devuelve falso
empty($job1->horas); // Devuelve falso`

Consideraciones:
Este método mágico recibe un único argumento que es el nombre del atributo que se quiere analizar. Es igual de importante aclarar que la utilización de la función empty() también disparara la ejecución del método mágico __isset() ya que según el manual de PHP empty () es equivalente a negar un isset (! isset ($ variable)).

__unset()
Evento que lo dispara: la función unset() de PHP permite destruir una variable, pero si quisiéramos utilizar la función unset() para intentar destruir un atributo que no está definido o inexistente en un objeto deberiamos definir primero el método mágico __unset. Este método es llamado automáticamente cuando se invoca la función unset() sobre un atributo inaccesible o no definido de un objeto.

Finalidad: Permite programar acciones con posterioridad a la invocación de la función unset().

Sintaxis:
`class Job
{
/* Propiedades */
private $titulo;
public $descripcion;
public $visible = true;
public $meses;
private $tutor;

/* Constructor */

public function __construct($contTitulo, $contDescripcion)
{
    $this->agregarTitulo($contTitulo);
    $this->descripcion = $contDescripcion;
}

function __unset($atributo) {

 		return unset($this->$atributo);
   
}  

} /* Fin de la clase */

unset($job1->titulo); // Devuelve falso`

Consideraciones:
Este método mágico recibe un único argumento que es el nombre del atributo que se quiere destruir.

__toString ()
Evento que lo dispara: este método es llamado luego de la invocación de las funciones de impresión echo(), print() y printf().

Finalidad: Permite asociar un string a un objeto, que será mostrado si dicho objeto es invocado como una cadena (por ejem: echo $objeto).

Sintaxis:
`class Job
{
/* Propiedades */
private $titulo;
public $descripcion;
public $visible = true;
public $meses;
private $tutor;

/* Constructor */

public function __construct($contTitulo, $contDescripcion)
{
    $this->agregarTitulo($contTitulo);
    $this->descripcion = $contDescripcion;
}

public function __toString() {  

 		return $this->$titulo;
   
}  

} /* Fin de la clase */

$job1 = new Job(‘Programador PHP’, ‘Este es un trabajo increible’);

echo $job1; // Devuelve Programador PHP`

Consideraciones:
Este método no recibe argumentos y si no lo definiéramos e intentáramos imprimir $job1 daría un error indicando que no se puede convertir el objeto a un string.

__sleep ()
Evento que lo dispara: este método es llamado luego de la invocación de la función serialize().

Finalidad: Permite determinar los atributos que queremos mostrar en la representación del objeto (serialización).

Sintaxis:
`class Job
{
/* Propiedades */
private $titulo;
public $descripcion;
public $visible = true;
public $meses;
private $tutor;

/* Constructor */

public function __construct($contTitulo, $contDescripcion)
{
    $this->agregarTitulo($contTitulo);
    $this->descripcion = $contDescripcion;
}

public function __sleep() {  

return array(“titulo”, “descripcion”);

}  

} /* Fin de la clase */

$job1 = new Job(‘Programador PHP’, ‘Este es un trabajo increible’);

$job1Serializado = serialize($job1); `

Consideraciones:
La función serialize() de PHP permite representar objetos como cadenas con el objetivo final de poder ser almacenados, por ejemplo en una base de datos. El problema de esta función es que convierte a cadena todos los atributos del objeto, independientemente de su ámbito, esto quiere decir que si un atributo está declarado como private o protected en el objeto, de todas maneras será serializado. En el ejemplo de arriba vemos como con el método mágico __sleep podemos definir que atributos vamos a representar en la serialización del objeto.

__wakeUp ()
Evento que lo dispara: este método es llamado luego de la invocación de la función unserialize().

Finalidad: Permite programar una acción que se ejecutara inmediatamente después de la ejecución de la función unserialize().

Sintaxis:
`class Job
{
/* Propiedades */
private $titulo;
public $descripcion;
public $visible = true;
public $meses;
private $tutor;
private $dbConnection;

/* Constructor */

public function __construct($contTitulo, $contDescripcion)
{
    $this->agregarTitulo($contTitulo);
    $this->descripcion = $contDescripcion;
}

public function __wakeUp() {  

$this->dbConnection = DB::connect();

}  

} /* Fin de la clase */

$job1 = new Job(‘Programador PHP’, ‘Este es un trabajo increible’);

$job1Serializado = serialize($job1);

$job1DesSerializado = unserialize($job1Serializado);`

Consideraciones:
Los casos de uso más comunes del método __wakeUp son los de, por ejemplo: restablecer la conexión con la base de datos, o alterar algún atributo del objeto.

__invoke ()
Evento que lo dispara: este método es llamado cuando se intenta invocar un objeto como si se tratara de una función.

Finalidad: Permite controlar el comportamiento de un objeto cuando este intenta ser llamado como a una función. Es decir, Si no definiéramos __invoke y tratáramos de utilizar el objeto como si se tratara de una función obtendremos un error.

Sintaxis:
`class Job {
private $title;
public $description;
public $visible;
public $months;

/* Metodo para setear titulo */
public function setearTitulo ($titulo) {
    return $this -> title = $titulo;
}

public function __invoke($argumento)
{
    echo $argumento;
}

}

$job1 = new Job(‘Programador PHP’, ‘Este es un trabajo increible’);

$job1(‘holaaa’); // holaaa`

Escribe tu comentario
+ 2
1
31544Puntos

Excelente tutorial , claro y preciso

Gracias por tomarte el tiempo al realizar esto,

1
4471Puntos

Muy bien hecho y muy bien explicado. Gracias.