Qué son los métodos mágicos de PHP

Una de las características que más me gusta de PHP son los métodos «mágicos».

En realidad, como en la vida real, no se trata de magia como tal, si no de buenos trucos.

De lo que se trata en este caso es de métodos que son invocados automáticamente (ante ciertos sucesos o eventos).

La principal característica que tienen estos métodos es que sus nombres comienzan con __ (doble underscore).

Si venís programando con objetos en PHP (al menos desde la versión 5), reconocerás estos (Especialmente el primero):

__construct

__destruct

Puede que no lo supieras, pero el constructor y destructor de la clase pertenecen a un grupo más grande de métodos (conocidos como «mágicos»).

Veamos algunos de ellos:

__toString

Este es otro de los más conocidos.

Su función es retornar una cadena (string) que represente al objeto.

Por ejemplo, si tuviéramos una clase Persona:

<?php

class Persona
{
     private $nombre;
     private $apellido;

     public function __construct( $nombre, $apellido )
     {
              $this->nombre = $nombre;
              $this->apellido = $apellido;
      }
}

Podría resultar interesante que, al momento de imprimir por pantalla los datos de la persona se viera su nombre y su apellido.

En este escenario podríamos definir un método __toString de la siguiente forma:

public function __toString()
{
    return $this->nombre.' '.$this->apellido;
}

Y luego hacer algo como:

$persona = new Persona( "Mauro", "Chojrin" );

echo $persona;

Cuando el intérprete lea echo $persona automáticamente buscará en la definición de la clase Persona un método __toString y, si lo encuentra, lo invocará.

Otros métodos mágicos interesantes

Como decía, existen varios métodos mágicos que vale la pena conocer:

__call

El método __call es invocado en forma automática cuando se realiza una llamada a un método no definido explícitamente.

En nuestro ejemplo anterior, sería el caso de invocar algo como $persona->intercambiar();.

Lo primero que hará el intérprete será buscar un método específico llamado «intercambiar», al no encontrarlo buscará una definción de un método __call. En caso de encontrarla lo invocará pasando como parámetros el nombre del método buscado («intercambiar» en este caso y la lista de argumentos).

La definición del método __call será algo como:

public function __call( $metodo, array $argumentos )
{
  ...
}

Este método es muy útil cuando se quiere armar familias de métodos similares.

El ejemplo más claro que me viene a la mente es el que usaba Doctrine en su versión 1.

Tenía un método findBy() que recibía un array de criterios de búsqueda.

Muchas veces era muy cómodo poder escribir algo como findByName() (Donde «Name» se correspondía con el nombre de un campo de la tabla en cuestión).

Es claro que Doctrine no puede adivinar todos los nombres de campos que a uno se le pueden ocurrir (y generar un método findByX()para cada uno…).

Ahí entonces una solución posible (basada en __call) es algo como:

public function __call( $method, array $arguments )
{
   $find = "findBy";

   if ( substr( $method, 0, strlen( $find ) ) == $find ) {
       $field = substr( $method, strlen( $find ) );
    
       return $this->findBy( [ $field => $arguments[0] ] );
   }
}

De esta forma es posible llamar a cualquier método findByX como si estuviese definido.

__set y __get

Los métodos __set y __get son invocados cuando se intenta asignar (u obtener) una variable no pública de una clase.

El contar con estos métodos permite, por ejemplo, ahorrar algo de código (No se requiere escribir un setter/getter para cada propiedad):

        public function __set( string $var, $val )
        {
                $this->$var = $val;
        }

        public function __get( string $var )
        {
                return $this->$var;
        }

Y luego:

$persona = new Persona( "Mauro", "Chojrin" );
echo $persona->nombre.PHP_EOL;
$persona->apellido = "Perez";
echo $persona.PHP_EOL;

Claro que, en este caso, bien podríamos haber dejado las variables como públicas y era más fácil, ¿cierto? :p

Pero el tener estos métodos me permite también, por ejemplo, crear propiedades virtuales:

        public function __set( string $var, $val )
        {
                if ( $var === "nombreCompleto" ) {
                        $parts = preg_split('/ /', $val);
                        $this->nombre = $parts[0];
                        $this->apellido = $parts[1];
                } else {
                        $this->$var = $val;
                }
        }

        public function __get( string $var )
        {
                if ( $var === 'nombreCompleto' ) {

                        return $this->__toString();
                }
                return $this->$var;
        }

Y al final:

$persona = new Persona( "Mauro", "Chojrin" );
$persona->nombreCompleto= "Miguel Perez";
echo $persona->nombre.','.$persona->apellido.PHP_EOL;

Más métodos mágicos

Hay unos cuántos métodos mágicos más (algunos más útiles que otros, cierto) que podés consultar en la documentación oficial de PHP.

Esta es una característica bastante avanzada que a veces se conoce también como meta-programación.

mchojrin
Publicada el
Categorizado como Misceláneos Etiquetado como

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes

¿Te quedó alguna duda? Publica aca tu pregunta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.