2013-02-04 7 views
5

コードは言葉よりも優れ語る:相対的な名前空間とcall_user_func()

namespaces.php

<?php 

namespace foo; 

use foo\models; 

class factory 
{ 
    public static function create($name) 
    { 
     /* 
     * Note 1: FQN works! 
     * return call_user_func("\\foo\\models\\$name::getInstance"); 
     * 
     * Note 2: direct instantiation of relative namespaces works! 
     * return models\test::getInstance(); 
     */ 

     // Dynamic instantiation of relative namespaces fails: class 'models\test' not found 
     return call_user_func("models\\$name::getInstance"); 
    } 
} 

namespace foo\models; 

class test 
{ 
    public static $instance; 

    public static function getInstance() 
    { 
     if (!self::$instance) { 
      self::$instance = new self; 
     } 

     return self::$instance; 
    } 

    public function __construct() 
    { 
     var_dump($this); 
    } 
} 

namespace_test.php:I場合

<?php 

require_once 'namespaces.php'; 

foo\factory::create('test'); 

としては、コメントcall_user_func()の中に完全修飾名を使用してください。これは期待どおり動作しますが、もし私が相対ネームパックそれはクラスが見つかりませんでした–しかし、直接インスタンシエーションが動作します。私は何か、またはそのの奇妙なを逃していますか?

+1

これは設計によるものだと思います。 'defined()'、 'constant()'などの関数にも同じ規則が適用されます。[このコメント](http://www.php.net/manual/en/function.defined.php#110530)をチェックしてください。 。 – Passerby

答えて

7

コールバックでは、完全修飾クラス名を使用する必要があります。

Example #3 call_user_func() using namespace name

<?php 

namespace Foobar; 

class Foo { 
    static public function test() { 
     print "Hello world!\n"; 
    } 
} 

call_user_func(__NAMESPACE__ .'\Foo::test'); // As of PHP 5.3.0 
call_user_func(array(__NAMESPACE__ .'\Foo', 'test')); // As of PHP 5.3.0 

を参照してください。私はcall_user_funcは同様にグローバルスコープからのコールバックを実行し、グローバルスコープからの関数であるためであると考えています。いずれにせよ、最初の文章を見てください。

はまた、完全修飾名(名前空間接頭辞を持つクラス名)を使用する必要があります

一つを述べExample #2 Dynamically accessing namespaced elements上記の注を参照してください。

+2

私は尋ねる前にこのマニュアルを見たことがありましたが、それは単なる例であると考えましたが、それはルールであることは明らかです。ありがとうございました! :) –

+1

私は完全にセクション["名前空間と動的言語機能"](http://php.net/namespaces.dynamic)をマニュアルから逃したと告白しました...もう一度指摘してくれてありがとう私はマニュアルを読むときに私はもっと注意を払うよ! :) –

1

現在のバージョンのPHPでは、文字列を使用してクラス名を参照する場合、その完全な名前空間で完全修飾されている必要があります。それは素晴らしいことではありませんが、それはそうです。

今後のPHP v5.5には、新しいClassname::class構文を提供することで、FQNクラス名を文字列に入れるのではなく、これに対処する機能が追加されます。この詳細については

、ここでは関係PHPのRFCのページを参照してください:https://wiki.php.net/rfc/class_name_scalars

あなたのコードは次のようになります。正確ではないかもしれない

return call_user_func([models\$name::class,"getInstance"]); 

を。私は確認するためにテストする5.5のコピーを持っていません。しかし、いずれにしても、新しい構文は、あなたのようなユースケースの方がずっと優れています。

+0

彼らはそれを認識していることを知っていることは素晴らしいことです。 :) –