Clases anónimas en PHP 7

Crear instancias de objetos de las clases es una acción bastante sencilla. Usamos la nueva palabra clave, seguida de un nombre de clase y posibles parámetros del constructor. La parte del nombre de la clase implica la existencia de una clase previamente definida. Aunque es raro, hay casos en los que las clases solo se usan durante la ejecución. Estos casos raros hacen que sea forzado forzar una definición de clase por separado cuando sabemos que la clase solo se usa una vez. Para abordar este desafío de verbosidad, PHP introdujo una nueva funcionalidad llamada clases anónimas.

Si bien el concepto de clases anónimas ha existido durante bastante tiempo en otros idiomas, PHP solo llegó a él en la versión PHP 7.

La sintaxis de las clases anónimas es bastante sencilla, que es la siguiente:

$obj = new class() {};
$obj2 = new class($a, $b) {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
};

Usamos la nueva palabra clave, seguida de la palabra clave class, seguida de los parámetros opcionales del constructor, y finalmente el cuerpo de la clase empaquetado en llaves. Ambos objetos se instancian como un tipo class@anonymous. La funcionalidad de los objetos instanciados a través de clases anónimas no es diferente de aquellos instanciados a través de clases nombradas.

En comparación con las clases con nombre, las clases anónimas son más o menos iguales, ya que pueden pasar parámetros, extender otras clases, implementar interfaces y usar traits.

Sin embargo, las clases anónimas no se pueden serializar. Intentar serializar una instancia de una clase anónima, como se muestra en el siguiente fragmento de código, arroja una serialización fatal de la clase class@anonymous no está permitido … error.

Hay algunas otras advertencias a tener en cuenta al usar clases anónimas. Anidar una clase anónima dentro de otra clase oculta los métodos o propiedades privados y protegidos de esa clase externa. Para evitar la limitación, podemos pasar las propiedades privadas y protegidas de la clase externa a un constructor de clase anónimo, de la siguiente manera:

interface Salary {
public function pay();
 }

trait Util {
public function format(float $number) {
return number_format($number, 2);
}
}

class User {
private $IBAN;
protected $salary;
public function __construct($IBAN, $salary) {
$this->IBAN = $IBAN;
$this->salary = $salary;
}
function salary() {
return new class($this->IBAN, $this->salary) implements Salary {
use Util;
private $_IBAN;
protected $_salary;

public function __construct($IBAN, $salary) {
$this->_IBAN = $IBAN;
$this->_salary = $salary;
}
public function pay() {
echo $this->_IBAN . ‘ ‘ . $this->format($this->_salary);
}
};
}
}
$user = new User(‘GB29NWBK60161331926819’, 4500.00);
$user->salary()->pay();

En este ejemplo de clase de usuario, tenemos un método de salario que devuelve una clase anónima. Para mostrar el uso más robusto de las clases anónimas, hacemos que implemente la interfaz Salary y use el trait Util. La interfaz Salary obliga a la clase anónima a implementar el método pay. Nuestra implementación del método pay requiere valores de IBAN y salary de la clase externa. Dado que una clase anónima no permite el acceso a miembros privados y protegidos de la clase externa, los pasamos a través de constructores de clase anónimos. Si bien el ejemplo general ciertamente no refleja las nociones de un buen diseño de clase, sí muestra cómo evitar la limitación de visibilidad del miembro.

También hay una opción para que una clase anónima busque los miembros privados y protegidos de la clase externa extendiendo la clase externa en sí. Sin embargo, esto requiere que el constructor de la clase anónima cree una instancia adecuada de la clase externa; de lo contrario, podríamos terminar con una advertencia, como un argumento faltante, para User :: __ construct ().

Aunque están definidos sin nombre, las clases anónimas aún obtienen un nombre interno.
Al utilizar el método get_class de PHP en una instancia de una clase anónima, se obtiene ese nombre, como se muestra en los siguientes ejemplos:

class User {}
class Salary {}
function gen() {
return new class() {};
}
$obj = new class() {};
$obj2 = new class() {};
$obj3 = new class() extends User {};
$obj4 = new class() extends Salary {};
$obj5 = gen();
$obj6 = gen();
echo get_class($obj); // class@anonymous/var/www/index.php0x27fe03a
echo get_class($obj2); // class@anonymous/var/www/index.php0x27fe052
echo get_class($obj3); // class@anonymous/var/www/index.php0x27fe077
echo get_class($obj4); // class@anonymous/var/www/index.php0x27fe09e
echo get_class($obj5); // class@anonymous/var/www/index.php0x27fe04f
echo get_class($obj6); // class@anonymous/var/www/index.php0x27fe04f
for ($i=0; $i<=5; $i++) {
echo get_class(new class() {}); // 5 x class@anonymous/var/www/index.php0x27fe2d3
}

Observando estas salidas, vemos que las clases anónimas creadas en la misma posición (función o bucle) producirán el mismo nombre interno. Aquellos con el mismo nombre devuelven verdadero para el operador igual (==) y falso para el operador de identidad (===), una importante consideración para evitar posibles errores.
El soporte para clases anónimas abre una puerta a algunos casos de uso interesantes, como simulacros de pruebas y anulaciones de clases en línea, las cuales, cuando se usan con prudencia, pueden mejorar la calidad del código y la legibilidad.

Comparte