Accessing protected property and method of sibling class is inconsistent
プロパティとメソッドでprotectedの可視性が異なる。
// ベースクラス
class BASE{
protected $foo = 'BASE property';
protected function bar(){ return 'BASE method';}
}
// 兄弟クラス
class OTHER extends BASE{
protected $foo = 'OTHER property';
protected function bar(){ return 'OTHER method';}
}
// 自分
class CHILD extends BASE{
// 兄弟クラスのprotectedプロパティを見る
public function hoge(){
$other = new OTHER();
echo $other->foo;
}
// 兄弟クラスのprotectedメソッドを呼ぶ
public function fuga(){
$other = new OTHER();
echo $other->bar();
}
}
$child = new CHILD();
$child->hoge(); // Fatal error: Uncaught Error: Cannot access protected property OTHER::$foo
$child->fuga(); // OTHER method ← ???
何故か兄弟クラスのprotectedなメソッドが見えてしまっています。
実際に走るメソッドはOTHER::bar()なのに、権限は何故かBASE::bar()のものが使われてしまっているようです。
試しにBASE::bar()を削除すると、正常にFatal error: Uncaught Error: Call to protected method OTHER::bar()
になります。
プロパティの場合は常にOTHER::fooの権限を見ているため、メソッドとプロパティで可視性が異なってしまっています。
まあ、これができたからといって特に問題が発生するとも思えませんけどね。
privateが見える
ところで、同一クラスであれば別インスタンスからもprivateが見えます。
class FOO{
private $bar;
public function __construct($bar = ''){
$this->bar = $bar;
}
public function getFooBar(FOO $foo){
return $foo->bar;
}
}
$foo1 = new Foo('foo1');
$foo2 = new Foo();
$foo2->getFooBar($foo1); // foo1
privateってこんな意味だったっけ?
と思ったらJavaやC++でも同じく、privateは同一クラス
からであれば読めるという仕様でした。
今までずっと同一インスタンス
じゃないといけないと思ってた。なぜなのか。
おまけ
Class FriendshipというRFCが提出されています。
friend認定することで、そのクラスからprotectedを読めるようにしようという内容です。
あまりAcceptされそうな気はしませんが。
// 相手
class OTHER{
protected $foo = 'OTHER';
public function getMe(ME $me){
return $me->bar;
}
}
// 自分
class ME{
friend OTHER; // 相手をフレンド認定
protected $bar = 'ME';
public function getOthers(OTHER $other){
return $other->foo;
}
}
$me = new ME();
$other = new OTHER();
$other->getMe($me); // ME 相手をフレンドだと思ってるので相手は自分のprotectedを読める
$me->getOther($other); // Cannot access protected property 相手はこっちをフレンドだと思ってないので読めない
どういう発想なんだこれ、と思ったけど実は先にC++に実装されているものらしい。
相手の情報を読むためには、自分側ではなく相手側にfriendsって書く必要があるので、どのようなときに役に立つ機能なのかさっぱり想像が付きません。
相手側にはfriend LoggerInterface;
とか元々書いておくから使う側で適当に実装すれ、とかそんなかんじですかね。