Dynamically call Class with variable number of par

2019-02-04 14:48发布

I know that it is possible to call a function with a variable number of parameters with call_user_func_array() found here -> http://php.net/manual/en/function.call-user-func-array.php . What I want to do is nearly identical, but instead of a function, I want to call a PHP class with a variable number of parameters in it's constructor.

It would work something like the below, but I won't know the number of parameters, so I won't know how to instantiate the class.

<?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条回答
在下西门庆
2楼-- · 2019-02-04 15:15

You can do that using 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" );

Basically, you simply pass the result of func_get_args to the constructor of your class, and let it decide whether it is being called with an array of arguments from that function, or whether it is being called normally.

This code outputs

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

Hope that helps.

查看更多
放荡不羁爱自由
3楼-- · 2019-02-04 15:16

I've found here

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

the example:

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

But can somebody tell me if there is an example for classes with protected constructors?

查看更多
唯我独甜
4楼-- · 2019-02-04 15:20

You can do the following using ReflectionClass

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

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

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

Edit:

In php 5.6 you can achieve this with Argument unpacking.

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

$myClassInstance = new $myClass(...$myParameters); 
查看更多
成全新的幸福
5楼-- · 2019-02-04 15:35

I implement this approach a lot when function args are > 2, rather then end up with an Christmas list of arguments which must be in a specific order, I simply pass in an associative array. By passing in an associative array, I can check for necessary and optional args and handle missing values as needed. Something like:

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

I highly recommend using an associative array, however it is possible to use a 0-index array. You will have to be extremely careful when constructing the array and account for indices that have meaning, otherwise you will pass in an array with offset args and wreck havoc with your function.

查看更多
登录 后发表回答