21

コンストラクターに送信される引数の特定の配列を使用してクラスを作成するにはどうすればよいですか?次のようなもの:

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の両方で、クラスを変更せずに機能する必要があります。何か案は?

4

2 に答える 2

25

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

悪くないですよね?

于 2009-12-18T16:11:06.163 に答える
10

ファクトリメソッドパターンを見て、この例を確認してください

ウィキペディアから:

ファクトリメソッドパターンは、オブジェクト指向のデザインパターンです。他の作成パターンと同様に、作成されるオブジェクトの正確なクラスを指定せずにオブジェクト(製品)を作成する問題を処理します。

このために専用のファクトリを使用したくない場合でも、Volkerのコードを関数にラップすることができます。

/**
 * 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;
}
于 2009-12-18T16:12:18.407 に答える