13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

protectedなメソッドとプロパティで可視性が異なる

Posted at

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;とか元々書いておくから使う側で適当に実装すれ、とかそんなかんじですかね。

13
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?