2012-01-04 18 views
12

Sé que es posible llamar a una función con un número variable de parámetros con call_user_func_array() que se encuentra aquí ->http://php.net/manual/en/function.call-user-func-array.php. Lo que quiero hacer es casi idéntico, pero en lugar de una función, quiero llamar a una clase de PHP con un número variable de parámetros en su constructor.Llamar dinámicamente a clase con número variable de parámetros en el constructor

Funcionaría algo como el siguiente, pero no sabré la cantidad de parámetros, así que no sabré cómo crear una instancia de la clase.

<?php 
//The class name will be pulled dynamically from another source 
$myClass = '\Some\Dynamically\Generated\Class'; 
//The parameters will also be pulled from another source, for simplicity I 
//have used two parameters. There could be 0, 1, 2, N, ... parameters 
$myParameters = array ('dynamicparam1', 'dynamicparam2'); 
//The instantiated class needs to be called with 0, 1, 2, N, ... parameters 
//not just two parameters. 
$myClassInstance = new $myClass($myParameters[0], $myParameters[1]); 
+0

Su pregunta es un poco ambigua. Parece que estás diciendo que no sabes ahora cuántos argumentos tomará el constructor, pero se trata de una cantidad que se corregirá en tiempo de ejecución y quieres llamarla con el número correcto. ¿Es eso correcto? –

+0

@jburbage Sí ... Se definirá el nombre de la clase a instanciar y se definirán los parámetros para el constructor. Estoy extrayendo esa información de otra fuente.En aras de la simplicidad, dejé eso fuera de este código. Voy a comentar el código anterior para aclarar. – bmarti44

+3

¿Has visto [esta pregunta] (http://stackoverflow.com/questions/1569949/instantiating-a-new-php-class-with-one-or-many-arguments)? Las respuestas allí pueden resolver su problema. –

Respuesta

37

Usted puede hacer lo siguiente usando ReflectionClass

$myClass = '\Some\Dynamically\Generated\a'; 
$myParameters = array ('dynamicparam1', 'dynamicparam2'); 

$reflection = new \ReflectionClass($myClass); 
$myClassInstance = $reflection->newInstanceArgs($myParameters); 

manual de PHP: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php

Editar:

en PHP 5.6 se puede lograr esto con Argument unpacking.

$myClass = '\Some\Dynamically\Generated\a'; 
$myParameters = ['dynamicparam1', 'dynamicparam2']; 

$myClassInstance = new $myClass(...$myParameters); 
+0

Esto es realmente lo que terminé necesitando usar. Me pregunto si el uso de ReflectionClass terminará ralentizando mi código mucho. – bmarti44

+2

@ bmarti44 ¡depende de cómo va a usarlo! Aquí hay dos enlaces sobre el rendimiento de ReflectionClass http://stackoverflow.com/questions/294582/php-5-reflection-api-performance y http://blog.liip.ch/archive/2008/09/18/fotd- reflectionclass-newinstanceargs-args-is-slow.html Si ralentiza el rendimiento del código, puede almacenar en caché la estructura de clases. – satrun77

7

implemento este enfoque mucho cuando args función son> 2, en lugar de terminar con una lista de Navidad de los argumentos que deben estar en un orden específico, simplemente pase en una matriz asociativa. Al pasar una matriz asociativa, puedo verificar los argumentos necesarios y opcionales y manejar los valores faltantes según sea necesario. Algo como:

class MyClass 
{ 
    protected $requiredArg1; 
    protected $optionalArg1; 

    public function __construct(array $options = array()) 
    { 
     // Check for a necessary arg 
     if (!isset($options['requiredArg1'])) { 
      throw new Exception('Missing requiredArg1'); 
     } 

     // Now I can just localize 
     $requiredArg1 = $options['requiredArg1']; 
     $optionalArg1 = (isset($options['optionalArg1'])) ? $options['optionalArg1'] : null; 

     // Now that you have localized args, do what you want 
     $this->requiredArg1 = $requiredArg1; 
     $this->optionalArg1 = $optionalArg1;    
    } 
} 

// Example call 
$class = 'MyClass'; 
$array = array('requiredArg1' => 'Foo!', 'optionalArg1' => 'Bar!'); 

$instance = new $class($array); 

var_dump($instance->getRequiredArg1()); 
var_dump($instance->getOptionalArg1()); 

Recomiendo usar una matriz asociativa, sin embargo, es posible utilizar una matriz de 0 índices. Tendrás que ser extremadamente cuidadoso al construir la matriz y tener en cuenta los índices que tienen significado, de lo contrario pasarás una matriz con args desplazados y destruirás tu función.

+0

Usaría este método, pero. . . Una de las clases utilizadas requiere dos argumentos, y no fue escrita por mí. . . Así que tendré que irme con ReflectionClass. Gracias por este método, me aseguraré de usarlo en todas las clases nuevas creadas. – bmarti44

+0

También uso mucho este método, sin embargo, solo uso la matriz '$ options' para los parámetros estrictamente _optional_ y dejo que _compiler_ rompa los argumentos requeridos faltantes en la llamada al método. – MrWhite

0

Puede hacerlo utilizando func_get_args().

class my_class { 
    function __construct($first = NULL) { 
     $params = func_get_args(); 
     if(is_array($first)) 
      $params = $first; 
     // the $params array will contain the 
     // arguments passed to the child function 
     foreach($params as $p) 
      echo "Param: $p\n"; 
    } 
} 
function my_function() { 
    $instance = new my_class(func_get_args()); 
} 

echo "you can still create my_class instances like normal:"; 
$instance = new my_class("one", "two", "three"); 
echo "\n\n\n"; 
echo "but also through my_function:"; 
my_function("one", "two", "three"); 

Básicamente, sólo tiene que pasar el resultado de func_get_args al constructor de la clase, y dejar que decida si se está llamando con una serie de argumentos a partir de esa función, o si se está recibiendo una llamada normalmente.

Este código genera

you can still create my_class instances like normal: 
Param: one 
Param: two 
Param: three 

but also through my_function: 
Param: one 
Param: two 
Param: three 

Espero que ayude.

0

que he encontrado aquí

Is there a call_user_func() equivalent to create a new class instance?

el ejemplo:

function createInstance($className, array $arguments = array()) 
{ 
    if(class_exists($className)) { 
     return call_user_func_array(array(
      new ReflectionClass($className), 'newInstance'), 
      $arguments); 
    } 
    return false; 
} 

Pero puede que alguien me diga si hay un ejemplo para las clases con constructores protegidos?

Cuestiones relacionadas