5

man ページの 1 つによるとhttp://www.php.net/manual/en/language.oop5.static.php :

非静的メソッドを静的に呼び出すと、E_STRICT レベルの警告が生成されます。

ただし、クラスから呼び出しが行われた場合はそうではないようです。

error_reporting(-1);

class Test {
    private $id;
    function __construct($id) { $this->id = $id; }
    function id() { return $this->id; }

    function __toString() {
        return Test::id()
             . self::id()
             . static::id()
             . static::id()
             . call_user_func('Test::id')
             . call_user_func(array('Test', 'id'));
    }
}
$a = new Test('a');
$b = new Test('b');


echo "$a $b $a"; # aaaaaa bbbbbb aaaaaa
var_dump(error_get_last()); # NULL

PHP 5.4 でのテスト

デモ: http://codepad.viper-7.com/IKp9iX

私は実証したと信じています:

  • E_STRICT 警告は生成されません
  • そのphpは、静的メソッド呼び出しをインスタンスメソッド呼び出しに魔法のように修正します(インスタンス変数にアクセスすると、idこれが証明されます)。

編集- debug_backtrace (-> ) を __toString 呼び出しに挿入すると、「メソッド呼び出し」を意味するの呼び出し「タイプ」が生成される ことを追加したいと思います。

これはバグですか、それとも文書化された機能ですか?

4

2 に答える 2

5

(宣言クラスだけでなく)任意のクラス内で静的構文を使用して非静的関数を呼び出すと、非静的関数は、現在の$thisオブジェクトのコンテキストで呼び出されたかのように動作します。

つまり、クラス内で他のクラスのメソッドを使用でき、それらのメソッドはクラスの$thisがクラスの$ this であると想定します。チェックしない場合、または通常とまったく同じように動作します。InstanceOfget_class()

私がいつものように言うとき、彼らはあなたのクラスの $this が彼らのクラスの $this が持つであろう他のすべてのメソッドとプロパティを持っていると仮定することを意味ます.

これは (私が思うに) オブジェクト コンテキスト バインディングと呼ばれます。JavaScript では、関数が特定のオブジェクトにアタッチされているかのように動作するようにするには、これらcall()および/またはapply()メソッドを使用する必要があります。しかし、PHP では、非静的関数で静的構文を使用するだけで機能します。

これはC++でも機能したことを覚えていますが、メソッドが継承されたクラスに属している場合にのみ機能したかどうかは思い出せません(オーバーライドされているにもかかわらずアクセスしたいオーバーライドされたメソッド)。

この (非表示の) 機能を使用すると、実行時に新しい機能をオブジェクトに追加するDecoratorデザイン パターンを実装できます。コンパイル時に処理される言語機能の実装とは対照的に、この実装は実行時に処理されるため、動的に実行/元に戻すことができるという追加のボーナスを使用して、MixinsまたはTraits (PHP 5.4 がネイティブにサポートするようになりました) をシミュレートすることもできます。動的に実行/元に戻すことはできません。機能を変更するには、コードを変更する必要があります。

于 2012-06-22T23:43:05.417 に答える
2

私はそれが半文書化された機能だと思います:

非静的コンテキストでは、呼び出されたクラスはオブジェクト インスタンスのクラスになります。$this-> は同じスコープからプライベート メソッドを呼び出そうとするため、 static:: を使用すると異なる結果が得られる場合があります。もう 1 つの違いは、static:: は静的プロパティのみを参照できることです。

self::id()つまり、(私が理解しているように) 遅延静的バインディングを実装するために使用できます: static::id()Test.

于 2012-06-22T23:38:27.203 に答える