Подтвердить что ты не робот

Динамически вызывать класс с переменным числом параметров в конструкторе

Я знаю, что можно вызвать функцию с переменным числом параметров с помощью найденного здесь вызова_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]);
4b9b3361

Ответ 1

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

Изменить:

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

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

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

Ответ 2

Я много использую этот подход, когда функция args > 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-индексный массив. Вы должны быть предельно осторожны при построении массива и учетной записи для индексов, имеющих смысл, иначе вы передадите массив с смещенными аргументами и вредителями с вашей функцией.

Ответ 3

Вы можете сделать это с помощью 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

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

Ответ 4

Я нашел здесь

Существует ли эквивалент 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;
}

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