2009-12-18 66 views
19

如何創建一個具有給定數組參數的類以發送給構造函數?沿線的東西:是否有一個call_user_func()等同於創建一個新的類實例?

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。有任何想法嗎?

+2

爲什麼你想這樣做呢?你想解決什麼問題? – Skilldrick 2009-12-18 16:11:09

+0

@Skilldrick:在我的情況下,試圖實現一個簡單的依賴注入容器。 – 2010-03-28 20:58:19

+0

[如何在PHP中使用call調用構造函數\ _user \ _func \ _array]的可能重複(http://stackoverflow.com/questions/2409237/how-to-call-the-constructor-with-call-user- func-array-in-php) – Maks3w 2015-11-13 20:16:06

回答

24

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 

不是那麼糟,是嗎?

+0

請記住VolkerK的答案僅在PHP5中可用 – Mark 2009-12-18 16:13:30

+0

僅在PHP5中支持反射,但這是我的方式。 – 2009-12-18 16:13:43

+0

我建議不要在生產代碼中使用任何反射。這很慢。 – 2009-12-18 16:16:08

9

看一看在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; 
} 
相關問題