php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62045 public access to a protected method
Submitted: 2012-05-16 08:23 UTC Modified: 2012-05-16 18:31 UTC
From: gonzalo123 at gmail dot com Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 5.3.13 OS: Linux
Private report: No CVE-ID:
 [2012-05-16 08:23 UTC] gonzalo123 at gmail dot com
Description:
------------
This code works, but it shouldn't, because AnotherClass::foo is protected.

It works only if "OneClass" extends "AnotherClass". If we dont't extends 
"OneClass" with "AnotherClass" (in this example we don't need it) we will see the 
normal error:

Fatal error: Call to protected method AnotherClass::foo() from context 'OneClass'


Test script:
---------------
class AnotherClass {
    protected function foo() {
        return "bar";
    }
}
class OneClass extends AnotherClass {
    private $object;
    public function __construct(AnotherClass $object) {
        $this->object = $object;
    }
    public function myFunction() {
        return $this->object->foo();
    }
}
$obj = new OneClass(new AnotherClass());
echo $obj->myFunction();

Expected result:
----------------
Fatal error: Call to protected method AnotherClass::foo() from context 'OneClass'

Actual result:
--------------
"bar" (without Fatal error)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-05-16 08:51 UTC] cataphract@php.net
Access is granted on a class, not instance basis. This is by design.
 [2012-05-16 08:51 UTC] cataphract@php.net
-Status: Open +Status: Not a bug
 [2012-05-16 09:00 UTC] gonzalo123 at gmail dot com
But we are not accesing OneClass::foo. This access is allowed beacause of the 
extends,we should not have access to use $this->object->foo();

$this is an instance of OneClass (it extends AnotherClass) but $this->object (we 
load it with DI) is an instance of AnotherClass. foo is protected here and we are 
accesing as a public method.
 [2012-05-16 09:00 UTC] gonzalo123 at gmail dot com
-Summary: public access to a protectec method +Summary: public access to a protected method
 [2012-05-16 11:36 UTC] cataphract@php.net
$this->object is an instance of OneClass. $this->object->foo() is called. foo() is protected and was defined in the context of OneClass. The access is done in the context of AnotherClass.  AnotherClass is a subclass of OneClass (the context where foo() was defined). Therefore access is granted. I don't know what's your problem here.
 [2012-05-16 13:15 UTC] gonzalo123 at gmail dot com
$this->object is not an instance of OneClass. 
$this->object is an instance of AnotherClass (look at the constructor).
 [2012-05-16 14:14 UTC] cataphract@php.net
Right. But it doesn't change anything. The type is only important to decide what the foo() method is, and foo() is AnotherClass and OneClass.
 [2012-05-16 14:21 UTC] cataphract@php.net
read: "is the same in"
 [2012-05-16 15:10 UTC] anon at anon dot anon
Here is another case which shows access granted based on class and not instance:

$a = new A();
$a->other = new A();
$a->foo();

class A {
	var $other;
	
	private function bar() {}
	
	public function foo() {
		$this->other->bar(); // okay to access private member of other instance of the same class
	}
}

It's definitely a desirable feature in this case, because it allows public static factory methods with private constructors. I can't think of a simple use for the subclass protected access though.

The PHP manual states "Members declared protected can be accessed only within the class itself and by inherited and parent classes. Members declared as private may only be accessed by the class that defines the member." (http://php.net/manual/en/language.oop5.visibility.php), so this is at least working as documented. Note the terminology: "class", not "instance of class". Even if a rule change was desirable it couldn't be done without breaking backward compatibility.

I translated both code samples here to Java and C++ to get a second opinion, as it were. In Java, both are allowed (see here for the rule on protected access: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2.1). In C++, the second example with private access from the same class is allowed; however the protected example given in the original report is not ("error: 'const char* AnotherClass::foo()' is protected").
 [2012-05-16 18:20 UTC] cataphract@php.net
Actually in Java protected is on an instance basis (unlike private), but it also includes package access.
 [2012-05-16 18:31 UTC] gonzalo123 at gmail dot com
OK. We must take into account the difference between "class" and "instance of a 
class". IMHO the script should throw a error, but I understand the reasons.

So: Not a bug
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Wed Apr 16 04:02:11 2014 UTC