Динамически вызывать класс с переменным количеством параметров в конструкторе - PullRequest
14 голосов
/ 05 января 2012

Я знаю, что можно вызвать функцию с переменным числом параметров с помощью call_user_func_array (), найденного здесь -> http://php.net/manual/en/function.call-user-func-array.php. То, что я хочу сделать, почти идентично, но вместо функции я хочу вызвать класс PHP с переменным числом параметров в его конструкторе.

Это будет работать примерно так, как показано ниже, но я не буду знать количество параметров, поэтому я не буду знать, как создать экземпляр класса.

<?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]);

Ответы [ 4 ]

44 голосов
/ 05 января 2012

Вы можете сделать следующее, используя ReflectionClass

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

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

Руководство по PHP: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php

Edit:

В php 5.6 вы можете добиться этого с помощью Распаковка аргумента .

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

$myClassInstance = new $myClass(...$myParameters); 
7 голосов
/ 05 января 2012

Я часто реализую этот подход, когда аргументы функции> 2, вместо того, чтобы в конечном итоге получить рождественский список аргументов, который должен быть в определенном порядке, я просто передаю ассоциативный массив. Передавая ассоциативный массив, я могу проверять необходимые и необязательные аргументы и обрабатывать пропущенные значения по мере необходимости. Что-то вроде:

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());

Я настоятельно рекомендую использовать ассоциативный массив, однако можно использовать массив с 0 индексами. Вы должны быть предельно осторожны при создании массива и учитывать индексы, которые имеют значение, иначе вы передадите массив со смещенными аргументами и разрушите вашу функцию.

0 голосов
/ 05 апреля 2015

Я нашел здесь

Существует ли call_user_func () для создания нового экземпляра класса?

пример:

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

Но может ли кто-нибудь сказать мне, если есть пример для классов с защищенными конструкторами?

0 голосов
/ 22 декабря 2014

Вы можете сделать это, используя 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" );

По сути, вы просто передаете результат func_get_args конструктору вашего класса и позволяете ему решить, вызывается ли он с помощьюмассив аргументов этой функции, или она вызывается нормально.

Этот код выводит

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

Надеюсь, что поможет.

...