3

PHPマニュアルからのコードを以下に示します

<?php
class A {
    private function foo() {
        echo "success!\n";
    }
    public function test() {
        $this->foo();
        static::foo();
    }
}

class B extends A {
   /* foo() will be copied to B, hence its scope will still be A and
    * the call be successful */
}

class C extends A {
    private function foo() {
        /* original method is replaced; the scope of the new one is C */
    }
}

$b = new B();
$b->test();
$c = new C();
$c->test();   //fails
?> 

ここで何が起こっているのか正確に説明できる人はいますか?

なぜ foo() が B にコピーされるのでしょうか?

4

2 に答える 2

4

レイト スタティック バインディングが便利な理由を思い出しました。残念ながら、php.net の例は説明が不十分です。この(変更された)例を参照してください:

<?php
class A {
    private function foo() {
        echo __CLASS__;
    }
    public function test() {
        $this->foo();
        static::foo();
    }
}

class B extends A {
    public function foo()
    {
        echo __CLASS__;
    }
}

$b = new B();
$b->test();
?>

上記のコードを実行すると、動作することがわかり、AB. なんで?

  • test()は の public getter であるため機能するため、 type のオブジェクトから呼び出すか、 から継承するtype のオブジェクトからfoo()呼び出すかは問題ではありません。これは、それが含まれるクラスのプライベート メンバーに常にアクセスできるためです。定義されています。test()ABAtest()
  • 最初のケースでは、バインドがのスコープ内でローカルに行われるため、$this->foo();常に呼び出されますが、これは非常に望ましくない場合があります。このコメントを参照してください: http://www.php.net/manual/en/language.oop5.late-static-bindings.php#83502A::foo()A
  • 2 番目のケースでstatic::foo();は、インタプリタに$bの型を判断し、どのクラスで を試して検索するかを確認するように指示しますfoo()。この場合、B::foo()は のオーバーライド メソッドと見なされるA::foo()ため、基本的に、B::foo()存在する場合はそれが呼び出され、存在しない場合はインタープリターが を探しますA::foo()
  • プライベートとしてマークB::foo()して、私が提供した例を実行して、何が起こるかを確認してください。このテストと上記の私の暴言が問題を明確にしてくれると思います ;)

また、私は長い間 PHP を使用していないため、上記の点に対するコメントを受け付けます。

于 2012-06-17T16:09:24.417 に答える
2

fooB 自体にはコピーされません (継承されますが、表示されません。以下のゴードンのコメントを参照してください)。B は を継承しA->foo、これは を呼び出しますA->testecho __CLASS__実証するために、あなたが内部からtestそして(そしてエラーを引き起こしている呼び出しfooを削除する)ときに何が起こるかを見てください:static::foo()

class A {
    private function foo() {
        echo __CLASS__."->foo\n";
        echo "success!\n";
    }
    public function test() {
        echo __CLASS__."->test\n";
        $this->foo();
    }
}

出力:

A->test
A->foo
success!
A->test
A->foo
success!

これは、情報の隠蔽/カプセル化に関連する継承の基本の 1 つです。これにより、次のようなことができます。

class ListOfThings {
    // internal structure (top secret!)
    private $_list = array();

    // add item to list
    public function add($item) {
        $this->_list[] = $item;
    }

    // return number of items in list
    public function count() {
        return count($this->_list);
    }
}

class ListOfStates extends ListOfThings {

    // do we have all 50 states?
    public function allStatesListed() {
        return $this->count() === 50;
    }

    // try to access internal structure of ListOfThings
    public function accessInternalStructure() {
        sort($this->_list);
    }
}

$states = new ListOfStates;
$states->add('ME');
$states->add('NH');
$states->add('VT');
$states->add('RI');
$states->add('CT');
var_dump($states->count());
var_dump($states->allStatesListed());
$states->accessInternalStructure();

出力:

int(5)
bool(false)

Warning: sort() expects parameter 1 to be array, null given...

ご覧のとおり、ListOfStatesは のすべてのパブリック機能を使用できますがListOfThings、それらの機能はすべてプライベート変数 に依存しています$_list。とはいえ、ListOfStates直接操作することはできません$_list$_listで定義されているパブリック関数を介して間接的にのみ作用できListOfThingsます。

そのようなことの詳細については、PHP ドキュメントの可視性ページを確認してください。

于 2012-06-17T15:37:38.500 に答える