Existen funciones de PHP que nos permiten mandar a llamar una función o un método dentro de una clase, sin conocer el nombre de éstas o los parámetros que le vayamos a pasar, como: call_user_func o call_user_func_array.
Sin embargo, ¿cómo creamos o instanciamos un objeto cuando no sabemos ni el nombre ni el número de parámetros? Pongámoslo más sencillo, supongamos que tenemos la siguiente clase:
<?php
class Prueba
{
public function suma($param1, $param2)
{
return $param1 + $param2;
}
}
?>
Con lo que conocemos podríamos hacerlo de la siguiente forma:
<?php
$params = array(5, 3);
$result = call_user_func_array(array('Prueba', 'suma'), $params);
echo "La suma de {$params[0]} + {$params[1]} es igual a {$result}"; //Salida: La suma de 5 + 3 es igual a 8
?>
De ese modo podríamos tener una clase con un método al que le podemos pasar cuantos parámetros sean requeridos, pero esto no resuelve mi problema, dado que primero necesitamos saber el nombre de la calse y del método y, por supuesto, el número de parametros.
A donde se quiere llegar es a crear sólo el objeto, sin llamar a algun método, tal vez podría solucionarse utlizando ‘__construct’, en la parte de la funcion donde indicamos el método a invocar, pero que hay de los parámetros, aun necesito saber cuantos son requeridos, necesito algo parecido a esto:
call_user_func_array('ClassName', array($param1, $param2, $param3, ..., $paramN));
Para ésto existe la serie de clases Reflection de PHP, que nos permite hacer ingeniería de reversa en clases, interfaces, funciones, métodos y extensiones.
<?php
function create_user_class_array($className, $params = array())
{
$reflection = new ReflectionClass($className);
return $reflection->newInstanceArgs($params);
}
class Test
{
public $output;
public function __construct()
{
$this->output = "Este objeto no tiene parametros";
}
}
class Test2
{
public function __construct($param1, $param2)
{
echo "Este objeto tiene 2 parametros: {$param1} y {$param2}";
}
}
class Test3
{
protected $params;
public function __construct($param1, $param2, $param3)
{
$this->params = array($param1, $param2, $param3);
}
public function showParams()
{
echo "Este objeto tiene 3 parametros: {$this->params[0]}, {$this->params[1]} y {$this->params[2]}";
}
}
//Test 1
$test = create_user_class_array('Test');
echo $test->output; //Salida: Este objeto no tiene parametros
$test2 = create_user_class_array('Test2', array('uno', 'dos')); //Salida: Este objeto tiene 2 parametros: uno y dos
$test3 = create_user_class_array('Test3', array('uno', 'dos', 'tres'));
$test3->showParams(); //Salida: Este objeto tiene 3 parametros: uno, dos y tres
Y listo, problema resuelto, al llamar a la funcion create_user_class_array() me instancia el objeto haciendo uso del Reflection y no dependo de saber los parametros, ¿cómo o dónde lo ocupo?, que tal si tenemos un método mágico __call, por ejemplo:
<?php
class MyTest
{
public function __call($className, array $params)
{
//Si el código fuera como el de siguiente,
//return new $className($params);
//marcaria error porque la clase $className puede requerir más de un parámetro y no necesariamente array
//utilizaremos lo siguiente:
$reflection = new ReflectionClass($className);
return $reflection->newInstanceArgs($params);
}
}
$obj = new MyTest;
echo $obj->Test1()->output;
$obj->Test2('uno', 'dos');
$obj->Test3('uno', 'dos', 'tres')->showParams();
$obj->AnyClass('my param', 1, 3.5, array('x', 'y'));
Ahora podemos crear objetos on-the-fly.
