metodos-magicos-php

¿Alguna vez te has preguntado cómo funcionan ORMs como Eloquent? Eloquent y otros ORMs en PHP hacen uso de algo llamado Métodos mágicos

Los métodos mágicos mágicos los provee PHP y nos permiten realizar ciertas tareas orientadas a objetos.

Los métodos mágicos identifican por el uso de dos guiones bajos “__” como prefijo, y funcionan como interceptores que se llaman automáticamente cuando ocurre una condición.

__get()

Este método se llama cuando intentamos acceder a una propiedad no accesible, acepta como parámetro un valor que es el nombre de la propiedad y deberíamos devolver el valor «virtual» de dicha propiedad. Vamos a realizar un ejemplo:

Para comenzar crearemos una clase, llamada Inflector, con un método llamado «studly» el cual recibirá una cadena de palabras divididas por guion bajo “_”, y regresará la misma cadena pero en formato CamelCase, por ejemplo: numero_dias regresará NumeroDias.

class Inflector {
    public static function studly($snakedString)
    {
        $array = explode('_', $snakedString);
        $array = array_map('ucfirst', $array);
        return implode('', $array);
    }
}

 

Ahora crearemos una clase base para todas las entidades del proyecto en la cual utilizaremos el método mágico __construct en donde, al crear una clase, recibiremos por parámetros todas las propiedades de la misma en formato array y se las asignaremos a la variable $properties, así podemos crear diferentes entidades con «N» propiedades. Este parámetro será opcional.

class Entity {

    protected $properties; //variable en donde guardamos todas las propiedades de la entidad

    /**
       Usamos el método mágico __construct para recibir las propiedades en un arreglo,
       y asignarlas a la variable $this->properties
    */
    public function __construct(array $values = array())
    {
        // Descomenta el var_dump si quieres comprobar que el metodo se esta invocando
        // var_dump($values);
        $this->properties = $values;
    }


    /**
      este es el método mágico __get cuando se ejecute al llamar a una propiedad fuera del objeto
      nosotros delegaremos la responsabilidad de devolver el valor de la propiedad al método getProperty
    */
    public function __get($name)
    {
        return $this->getProperty($name);
    }

    public function getProperty($name)
    {
        //Utilizamos la clase Inflector para que nos retorne la cadena en formato CamelCase
        $dynamicMethod = 'get' . Inflector::studly($name); 

        //Verificamos si existe un metodo dinamico para obtener la propiedad
        //Por ejemplo numero_dias intentara llamar al metodo getNumeroDias dentro del objeto
        if (method_exists($this, $dynamicMethod))
        {
            //Si existe lo llamamos
            return $this->$dynamicMethod();
        }

        //si no existe un método se regresa el valor de la propiedad de la entidad
        //en caso de que exista dentro del array properties
        if (isset ($this->properties[$name]))
        {
            return $this->properties[$name];
        }
        //en caso de no existir ni un método o propiedad con el nombre se regresa null
        return null;
    }

}

Creamos la clase User que extiende de la clase Entity, para poder hacer uso de toda la lógica ya mostrada.


class User extends Entity {

    public function getName()
    {
        return strtoupper($this->properties['name']);
    } //creamos un método getName que nos regresa el valor de la propiedad name en mayúsculas.

}

 

 


//instanciamos la clase y le mandamos las propiedades y valores aqui entra el __construct.
$user = new User(['name' => 'David', 'edad'=> 32, 'nacionalidad' => 'Mexicana']);

//imprimimos la propiedad name, se invoka la funcion __get(),
// que llama a la funcion getProperty()
// y como existe el metodo getName() éste se llama
// y nos regresa el nombre en mayúsculas:

die($user->name);

//si llamas a la propiedad nacionalidad die($user->nacionalidad);
//entonces nos regresara el valor de la propiedad.
die($user->nacionalidad);

//Esto nos regresaria NULL porque no existe la propiedad profesion
die($user->profesion);

Aquí utilizamos el método __construct() y __get() de una forma muy profesional y orientada a objetos, similar a como lo manejan ORMs como Eloquent.

__set()

Continuamos con los métodos y nos toca hablar de __set(). __set funciona de forma contraria a __get(), ya que nos sirve para asignar un valor a una propiedad no visible. Continuaremos con el ejemplo anterior  y solo agregaremos las funciones necesarias.

Este método se ejecuta cuando se le asigna un valor a una propiedad por ejemplo $user->name =»Jesus David»; es en este momento en donde, al no existir la propiedad name dentro del objeto, PHP llamará al método __set y dicho llamado nos servirá para realizar acciones como asignar el valor a la entidad.

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

Continuemos con el ejemplo, creamos una función que se llama setProperty para seguir utilizando nuestra clase «entidad» con N propiedades:

public function setProperty($name, $valor)
{
    $dynamicMethod = 'set' . Inflector::studly($name);

    if(method_exists($this, $dynamicMethod))
    {
        $this->$dynamicMethod($name, $valor);
    }
    else
    {
        $this->properties[$name] = $valor;
    }
}

En esta función revisamos si existe un método set con el nombre de la propiedad, si es así se ejecuta, de lo contrario asignamos el valor al array properties directamente.

Ejemplo de un método dinámico que podríamos invocar a través de __set:

public function setName($name, $valor)
{
    $this->properties['name'] = trim(strip_tags($valor));
}

Se pueden hacer operaciones como limpiar una variable antes de asignarla a la propiedad.

$user = new User();
$user->name = '   David   '; //se cambia el valor de la propiedad name
die($user->name); //regresa David sin las etiquetas HTML ni los espacios extras

 __isset()

Este nos sirve para saber si una propiedad existe dentro de una clase, y se ejecuta al hacer lo siguiente:

if (isset($user->name))
{
    die($user->name);
}

Comprobamos si existe la propiedad name. y si existe devolvemos TRUE, sino FALSE.


public function __isset($valor)
{
    return isset($this->properties[$valor]));
}

 __unset()

__unset nos sirve para eliminar una propiedad de la clase y se llama cuando ejecutamos:

unset($user->name);

Esto eliminará del array de $propeties la variable  que se le envía en este caso el nombre:

public function __unset($name)
{
    //echo "Eliminando '$name'\n";
    unset($this->properties[$name]);
}

Y lo podemos comprobar de la siguiente manera.

unset($user->name);

if(isset($user->name))
{
    die($user->name);
}
else
{
    die("No existe la propiedad");
}

Con esto terminamos la primera parte de los métodos mágicos.

En la siguiente entrega veremos mas métodos interesantes que nos ayudan y facilitan muchas tareas a la hora de programar.

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Aprende programación orientada a objetos: Patrón Factory Lección siguiente Abstracción con PHP y programación orientada a objetos