【问题标题】:Is there a call_user_func() equivalent to create a new class instance?是否有一个 call_user_func() 等效于创建一个新的类实例?
【发布时间】:2010-12-28 02:20:59
【问题描述】:

如何创建一个具有给定参数数组的类以发送到构造函数?大致如下:

class a {
    var $args = false;
    function a() {$this->args = func_get_args();}
}

$a = call_user_func_array('new a',array(1,2,3));
print_r($a->args);

理想情况下,这需要在 PHP4 和 PHP5 中工作,无需修改类。有什么想法吗?

【问题讨论】:

标签: php class php4


【解决方案1】:

ReflectionClass:newInstance()(或 newInstanceArgs())让你这样做。

例如

class Foo {
  public function __construct() {  
    $p = func_get_args();
    echo 'Foo::__construct(', join(',', $p), ') invoked';
  }
}

$rc = new ReflectionClass('Foo');
$foo = $rc->newInstanceArgs( array(1,2,3,4,5) );

编辑:没有 ReflectionClass 并且可能与 php4 兼容(抱歉,目前没有 php4)

class Foo {
  public function __construct() {  
    $p = func_get_args();
    echo 'Foo::__construct(', join(',', $p), ') invoked';
  }
}

$class = 'Foo';
$rc = new $class(1,2,3,4);

速度比较: 既然提到了反射速度,这里就做一个小(综合)测试

define('ITERATIONS', 100000);

class Foo {
  protected $something;
  public function __construct() {
    $p = func_get_args();
    $this->something = 'Foo::__construct('.join(',', $p).')';
  }
}

$rcStatic=new ReflectionClass('Foo'); 
$fns = array(
  'direct new'=>function() { $obj = new Foo(1,2,3,4); },
  'indirect new'=>function() { $class='Foo'; $obj = new $class(1,2,3,4); }, 
  'reflection'=>function() { $rc=new ReflectionClass('Foo'); $obj = $rc->newInstanceArgs( array(1,2,3,4) ); },
  'reflection cached'=>function() use ($rcStatic) { $obj = $rcStatic->newInstanceArgs( array(1,2,3,4) ); },
);


sleep(1);
foreach($fns as $name=>$f) {
  $start = microtime(true);
  for($i=0; $i<ITERATIONS; $i++) {
    $f();
  }
  $end = microtime(true);
  echo $name, ': ', $end-$start, "\n";
  sleep(1);
}

在我的(没那么快的)笔记本上打印

direct new: 0.71329689025879
indirect new: 0.75944685935974
reflection: 1.3510940074921
reflection cached: 1.0181720256805

这不是很糟糕,是吗?

【讨论】:

  • 仅 PHP5 支持反射,但我会这样做。
  • 我建议不要在生产代码中使用任何反射。速度很慢。
  • 很遗憾它只是 PHP5,但谢谢。可能会使用它来回退到 PHP4 的 eval 语句。速度对我的使用来说不是太大问题。
  • 在使用 eval() 之前,你真的应该先用 php4 测试新的 $class(1,2,3) 东西。我很确定它会起作用。工厂是一个很棒的基本模式 - 绝对值得花时间阅读它;-)
  • 使用new $class($args)方法有什么缺点吗?
【解决方案2】:

查看Factory Method pattern 并查看this example

来自维基百科:

工厂方法模式是一种 面向对象的设计模式。喜欢 其他创造模式,它处理 有创建对象的问题 (产品)没有指定 对象的确切类别 已创建。

如果您不想为此使用专用工厂,您仍然可以将wrap Volker's code 放入函数中,例如

/**
 * Creates a new object instance
 *
 * This method creates a new object instance from from the passed $className
 * and $arguments. The second param $arguments is optional.
 *
 * @param  String $className class to instantiate
 * @param  Array  $arguments arguments required by $className's constructor
 * @return Mixed  instance of $className
 */
function createInstance($className, array $arguments = array())
{
    if(class_exists($className)) {
        return call_user_func_array(array(
            new ReflectionClass($className), 'newInstance'), 
            $arguments);
    }
    return false;
}

【讨论】:

    猜你喜欢
    • 2016-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-21
    相关资源
    最近更新 更多