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