sábado, 20 de diciembre de 2014

Los métodos mágicos en PHP



Un método mágico es un método al que se llama automáticamente cuando se produce un acontecimiento.

Por ejemplo __construct es un método mágico. Se ejecuta automáticamente cuando instancia la clase que contiene __construct.

Los métodos mágicos __get y __set permiten leer o modificar los atributos que no existen y en los que el acceso está prohibido.

Retome el ejemplo al inicio del capítulo con la clase Animal:


Esta vez, el atributo color es privado y el atributo peso es público:

<?php
class Animal
{
// Declaración de atributos
private $color = "gris";
public $peso = 10;
public function __construct($color, $peso) // Constructor
//que solicita 2 argumentos.
{
echo ’Llamada al constructor.<br />’;
$this->color = $color; // Inicialización del color.
$this->peso = $peso; // Inicialización del peso.
}
//métodos públicos
public function comer ()
{
}
public function moverse ()
{
}
}
?>

Cuando crea una instancia de la clase Animal, puede acceder al atributo peso porque es público, pero no al atributo color porque es privado.

La página uso.php es:

<?php
//carga de clases
include(’Animal.class.php’);
//instanciar la clase Animal
$perro = new Animal("gris",8);
$perro->color = "negro";
echo $perro->color."<br />";
?>

Muestra un error porque intenta acceder directamente al atributo color, que es privado:

Llamada al constructor.

Fatal error: Cannot access private property Animal::$color in C:\Program Files\EasyPHP-DevServer-13.1VC11\data\localweb\Objeto\ uso.php on line 9

Ahora añada los métodos mágicos __get y __set en la clase Animal:

<?php
class Animal
{
// Declaración de atributos
private $color = "gris";
public $peso = 10;
private $tab_atributos = array();
public function __construct($color, $peso) // Constructor
//que solicita 2 argumentos.
{
echo ’Llamada al constructor.<br />’;
$this->color = $color; // Inicialización del color.
$this->peso = $peso; // Inicialización del peso.
}
//métodos mágicos
public function __get($nombre)
{
echo "__get <br />";
if (isset ($this->tab_atributos[$nombre]))
return $this->tab_atributos[$nombre];
}
public function __set($nombre, $valor)
{
echo "__set <br />";
$this->tab_atributos[$nombre] = $valor;
}
public function __isset($nombre)
{
return isset ($this->tab_atributos[$nombre]);
}
//métodos públicos
public function comer ()
{
...
}
public function moverse ()
{
...
}
}
?>

Estos métodos se activan automáticamente si el atributo es privado o no existe. Almacenan el valor en la tabla $tab_atributos, y en el índice, el nombre del atributo. El método __isset($atributo) permite saber si existe el atributo.

La página uso.php:

<?php
//carga de clases
include(’Animal.class.php’);
//instanciar la clase Animal
$perro = new Animal("gris",8);
if (isset($perro->color)) {
echo "El atributo color existe.<br />";
}
else {
echo "El atributo color no existe.<br />";
}
$perro->color = "negro";
echo $perro->color."<br />";
if (isset($perro->peso)) {
echo "El atributo peso existe.<br />";
}
else {
echo "El atributo peso no existe.<br />";
}
$perro->peso = 25;
echo $perro->peso."<br />";
?>

Da como resultado:

Llamada al constructor.
El atributo color no existe.
__set
__get
Negro
El atributo peso existe.
25

Explicación:

$perro = new Animal("gris",8); da como resultado: Llamada al constructor.

isset($perro->color); devuelve falso, ya que no se puede acceder al atributo color, que es privado; por lo tanto, muestra: El atributo color no existe.

$perro->color = "negro"; da como resultado: __set. El atributo color es privado; por lo tanto, no se puede acceder a él y llama automáticamente a __set y el valor se almacena en la tabla $tab_atributos.
echo $perro->color."<br />"; da como resultado: __get y negro. El atributo color siempre es privado; por lo tanto, llama automáticamente a __get para mostrar el color.

isset($perro->peso); devuelve verdadero porque el atributo peso es público, se puede acceder a él y por lo tanto muestra: el atributo peso existe.

$perro->peso = 25; no muestra nada porque no llama a la función __set. El atributo peso es público, puede acceder directamente a él.

echo $perro->peso."<br />"; da como resultado 25. El atributo peso es público y por lo tanto puede acceder directamente a él.

Para eliminar un atributo que el método mágico __set ha añadido, debe ejecutar el método mágico __unset($atributo), que eliminará el atributo de la tabla $tab_atributos.

Añada este método en la clase Animal:

public function __unset($nombre)
{
if (isset($this->tab_atributos[$nombre]))
unset($this->tab_atributos[$nombre]);
}

Para terminar, los métodos mágicos __call y __callStatic permiten llamar a los métodos privados o que no existen. La función method_exist() comprueba si un método existe en
un objeto. Toma como argumento el objeto y el nombre del método. Devuelve true si el método existe y false si no.

La clase Animal con un método público comer() y un método privado moverse() se convierte en:

<?php
class Animal
{
// Declaración de atributos
private $color = "gris";
public $peso = 10;
private $tab_atributos = array();
public function __construct($color, $peso) // Constructor
//que solicita 2 argumentos.
{
echo ’Llamada al constructor.<br />’;
$this->color = $color; // Inicialización del color.
$this->peso = $peso; // Inicialización del peso.
}
//métodos mágicos
public function __get($nombre)
{
echo "__get <br />";
if (isset ($this->tab_atributos[$nombre]))
return $this->tab_atributos[$nombre];
}
public function __set($nombre, $valor)
{
echo "__set <br />";
$this->tab_atributos[$nombre] = $valor;
}
public function __isset($nombre)
{
return isset ($this->tab_atributos[$nombre]);
}
public function __call($nombre, $argumentos)
{
echo "El método ".$nombre." no es accesible. Sus argumentos
eran los siguientes :".implode($argumentos, ’, ’)."<br />";
if(method_exists($this, $nombre))
{
$this->$nombre(implode($argumentos, ’, ’));
}
}
public static function __callStatic($nombre, $argumentos)
{
echo "El método estático ".$nombre." no es accesible.
Sus argumentos eran los siguientes :".implode($argumentos, ’, ’)
."<br />";
if(method_exists(__CLASS__, $nombre))
{
echo __CLASS__.’::’.$nombre.’<br />’;
self::$nombre(implode($argumentos, ’, ’));
}
}
//método público
public function comer()
{
echo "Método público comer() <br />";
}
//método privado
private function moverse($lugar)
{
echo "Método privado moverse() <br />";
}
}
?>

La página uso.php:

<?php
//carga de clases
include(’Animal.class.php’);
//instanciar la clase Animal
$perro = new Animal("gris",8);
$perro->comer();
$perro->moverse("París");
?>

Da como resultado:

Llamada al constructor.
Método público comer()
El método moverse no es accesible. Sus argumentos eran los siguientes:París
Método privado moverse()

El código $perro->comer(); llama al método público comer(). Pero al método moverse($lugar), que es privado, no se puede acceder directamente. Llama al método mágico __call, comprueba que existe el método moverse($lugar)y llama al método moverse ($lugar).

Si el método moverse ($lugar) es estático, la llamada a la página uso.php es:

Animal::moverse("París");

Entonces llama al método mágico __callStatic.

Hay otros métodos mágicos que no se explican en este libro. Puede obtener más información sobre estos métodos en el manual de PHP, en la siguiente dirección: http://php.net/manual/es/language.oop5.magic.php



Espero haber ayudado en algo. Hasta la próxima oportunidad!









2 comentarios:

  1. Deberias usar algun SyntaxHighlighter para los codigos

    ResponderEliminar
    Respuestas
    1. Hola JohnC, gracias por la visita y el aporte de tu comentario!
      Estoy actualizando las páginas con código para agregarle referencia a un SyntaxHighlighter.
      Sería bueno que me dejaran un comentario en las páginas que están sin SyntaxHighlighter.

      Los mejores deseos! Hasta cualquier momento!

      Eliminar