2016-11-19 8 views
1

call_user_func_arrayメソッドを呼び出したクラスの名前を調べることは可能ですか?ここでは例です:call_user_func_arrayを呼び出したクラスを確認する

// ClassA 
public static function __callStatic($method, $args) 
{ 
    return call_user_func_array([ClassB::some_method(static::$some_arg), $method], $args); 
} 

// ClassB 
public static function some_method($some_arg) { 
    // how do I find out that some_method was called by ClassA? 
} 

some_methodは、それがClassAによって呼び出されたことを知っているために目標があります。また、ClassB::some_method(static::$some_arg)がメソッドを静的に呼び出し、の$methodがチェーンされていることにも注意してください。

補足として、call_user_func_arrayreturn DB::some_method(static::$some_arg)->$method(extract($args));に置き換えようとしましたが、期待通りに機能しませんでした。理由は何ですか?

編集

私は最初の質問に少し複雑です。クラスClassA_Childがあることを今想像:

class ClassA_Child extends ClassA {} 

ClassA_ChildClassBのメソッドを呼び出すことができます - some_method。コールは、ClassA_ChildClassAのサブクラスであるため、これが有効である

ClassA_Child::some_method; 

だろう。しかし、私は次の操作を実行した場合:バックトレースはsome_methodは、基本クラスClassA、ないClassA_Childによって呼び出されたことを示していること

// ClassB 
public static function some_method($some_arg) { 
    $bt = debug_backtrace(); 
    $caller_class = (isset($bt[1]['class']) ? $bt[1]['class'] : null); 
    echo $caller_class; // ClassA, and NOT ClassA_Child! 
} 

注意。それを修正する方法はありますか?

+0

私は、あなたの編集を見ました[ 1] $ bt [2]?クラスを上に移動すると、静的呼び出しがClassAまたはClassA_Childで発生したかどうかを確認できます。 – Johnny

+1

some_methodには、正しい一貫性のある結果を返すパラメータセットが必要です。同じクラスのいくつかの場所から関数を呼び出す必要があり、わずかに異なる結果が必要な場合はどうでしょうか。また、このタイプのコーディングは、プロジェクトとチームが成長するにつれて、文書化し維持することが困難です。 – user2182349

答えて

1

一部のイントロはこの回答の対象です。まず最初に、(彼らのようなプログラマーがビールの前で社会的に夕食を取っているような)話をするのはいいと思うでしょう。なぜあなたはこのような複雑な間接参照をしたいと思っていました。私はかなり複雑なORMで作業しました。インダイレクションと抽象化の

もう一つの重要な注意点は、誰かが、おそらくあなたがないこのためdebug_backtrace()ソリューションとその理由を採用すべきことをいくつかの非常に哲学的引数でコメントすることです。確かに悪い習慣ですが、私もそれを使っています。ちょうど警告されて、非常に壊れやすいコーディングで、多くの状況がバックスタブの準備ができています。 __callStatic()直接ClassAの代わりのサブクラスで呼び出された場合

B::some_method (ciao) 
.. i was called by A 
C::other_method called 

更新#2

class A { 
    static $some_arg = "ciao"; 

    public static function __callStatic($method, $args) { 
    return call_user_func_array(array(B::some_method(static::$some_arg), $method), $args); 
    } 
} 

class B { 
    public static function some_method($some_arg) { 
    print "B::some_method (" . $some_arg . ")\n"; 

    // obtain the caller class 
    $bt = debug_backtrace(); 
    $caller_class = (isset($bt[1]['class']) ? $bt[1]['class'] : null); 
    print ".. i was called by " . $caller_class . "\n"; 

    return "C"; 
    } 
} 

class C { 
    public static function other_method($arg1, $arg2) { 
    print "C::other_method called\n"; 
    } 
} 

A::other_method(10, 20); 

出力:ここ

は、関連するコードでありますClassAClassA_Child::doSomething()など)の場合、次のliこの情報を得るためにコードを読み込みます。スクリプトが__callStatic()を直接呼び出すと(この場合は決して発生しないはずです)、この変更(コールスタックを1つ上のレベルに上げる)は、が失敗するとになります。

$caller_class = (isset($bt[2]['class']) ? $bt[2]['class'] : null); 

UPDATE

私は質問の "サイドノート" の部分のための私の答えを編集しなければなりませんでした。私はsome_method()が静的クラス名(基本的には文字列)を返すと考えていたので間違っていましたが、実際にインスタンスを返していました。

この場合、必要に応じてcall_user_func_array()を絶対に削除することはできますが、それを使用するのが私の推奨する解決方法です。あなたがやっている唯一の間違いは、extract($ args)の部分です。その関数はではありません。あなたはそれが実際に何かをしていると思います。あなたがここに必要なもの

は、この例のように、拡散演算子です:

class B { 
    static function factory() { 
    print "called B::factory()\n"; 
    return new C(); 
    } 
} 

class C { 
    function m($a, $b) { 
    print "called c::m() a=$a b=$b\n"; 
    } 
} 

$func_name = "m"; 
$func_args = array(10, 20); 
B::factory()->$func_name(...$func_args); 

は出力:私はあなたが単に$ BTを交換してみまし述べたように

called B::factory() 
called c::m() a=10 b=20 
+0

私はあなたの徹底的な答えに感謝します! 'debug_backtrace'に代わるより安全な方法はありますか?サイドノートについては、 'ClassB'の' some_method'が 'ClassB'のオブジェクトを返し、' call_user_func_array'で呼び出される$ methodがそのオブジェクトに連鎖しています。 – Alex

+0

いいえ、私は他の方法はないと思います。私が言及したように、実際には大きな練習ではないにしても、同じテクニックを使用します。もちろん、呼び出された関数自体に引数として '__CLASS__'を渡す以外には。 – Johnny

+0

ありがとうございます。私の問題は、 'ClassA'の子クラス(例えば' ClassAChild')が 'ClassB'では' some_method'を実際に呼び出し、 'ClassA'自体は呼び出さないということです。私は 'classA'をdebug_backtraceに入れます。 'ClassAChild'を得ることは可能ですか? – Alex

関連する問題