Bug #66670 [Nab]: property_exist cannot find private properties defined in superclass
| From: | requinix@php.net | Date: | Tue, 11 Feb 2014 01:01:18 +0000 |
| Subject: | Bug #66670 [Nab]: property_exist cannot find private properties defined in superclass | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-184250@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=66670&edit=1
ID: 66670
Updated by: requinix@php.net
Reported by: mpope at homeimprovementleads dot com
Summary: property_exist cannot find private properties
defined in superclass
Status: Not a bug
Type: Bug
Package: Class/Object related
Operating System: windows 7
PHP Version: 5.5.9
Block user comment: N
Private report: N
New Comment:
Re: first two replies
I think what you're missing is that even though $foo and $goo are not inherited and don't
"exist" in $this, they must clearly exist *somewhere* for A and B to be able to use them.
Here's three simple statements, all restating the same underlying rule:
1. $this->foo exists in an instance of A (1a) and in code inherited from A (1b)
2. $this->goo exists in an instance of B (2a) and in code inherited from B (2b)
3. $this->poo exists in an instance of C (3a) and in code inherited from C (3b)
They fully explain the output:
// C::__construct
bool(false) // $foo: neither 1a nor 1b apply
bool(false) // $goo: neither 2a nor 2b apply
bool(true) // $poo: both 3a and 3b apply
// B::__construct
bool(false) // $foo: neither 1a nor 1b apply
bool(true) // $goo: 2a does not apply but 2b does
bool(true) // $poo: 3a applies (3b does not)
// A::__construct
bool(true) // $foo: 1a does not apply but 1b does
bool(false) // $goo: neither 2a nor 2b apply
bool(true) // $poo: 3a applies (3b does not)
// check_scope
bool(false) // $foo: neither 1a nor 1b apply
bool(false) // $goo: neither 2a nor 2b apply
bool(true) // $poo: 3a applies (3b does not)
Previous Comments:
------------------------------------------------------------------------
[2014-02-11 00:19:14] mpope at homeimprovementleads dot com
And this might be worthy of its own ticket, but it looks like all magic methods use an incorrect
scope during execution. I have a __call() method that cannot access a private property declared in
the same class when __call() is invoked via a subclassed object.
In the context of the example script, if class 'a' had a __call() method defined and we
called $c->UnknownFunc(), the __call method in class 'a' would not be able to access
$foo, even though they're in the same class. And yet with $c->UnknownFunc() I can access
$poo from class a's __call() method even though $poo is defined in class 'c', not
class 'a' where the __call method is defined.
------------------------------------------------------------------------
[2014-02-10 23:22:52] mpope at homeimprovementleads dot com
Additionally if we're going to be strict to inheritance rules about private properties, we
shouldn't see private properties of our subclasses either. Just the private properties of the
currently scoped class. But in the example you'll notice that property_exist returns true for
both the current class's scope AND the 'c' subclass. Meaning in class a's
constructor I can see two private properties, $foo and $poo. By your statement I should only see
$foo.
------------------------------------------------------------------------
[2014-02-10 23:11:00] mpope at homeimprovementleads dot com
Ok, but there is still a bug in that if you call property_exists from the class proper, vs from some
externally defined method from the class you get different results. In the example I posted, the
check_scope() function should echo the same results as the explicit checks inside the constructors.
------------------------------------------------------------------------
[2014-02-08 00:31:50] requinix@php.net
It's a matter of inheritance, not accessibility: the subclasses do not inherit the private
properties of the superclasses. The properties really don't exist.
------------------------------------------------------------------------
[2014-02-08 00:15:14] mpope at homeimprovementleads dot com
Description:
------------
Despite reporting as fixed ( https://bugs.php.net/bug.php?id=50810 ) and closed
in 5.3.3 according to the change log, a small variation in the logic still produces a bug in 5.5.9.
The fix in 50810 only worked because the method checking the private property was in the same class
as the private property. If you attempt to check the private property of a superclass from the
subclass it reports false. Although I would normally expect this behavior, I think it is counter to
the statement found in the docs for property_exists in the change log section:
"5.3.0 This function checks the existence of a property independent of accessibility."
Test script:
---------------
<?php
function check_scope($ref) {
echo "vs\n";
var_dump(property_exists($ref, 'foo'));
var_dump(property_exists($ref, 'goo'));
var_dump(property_exists($ref, 'poo'));
echo "\n";
}
class a {
private $foo;
public function __construct() {
var_dump(property_exists($this, 'foo'));
var_dump(property_exists($this, 'goo'));
var_dump(property_exists($this, 'poo'));
check_scope($this);
}
}
class b extends a {
private $goo;
public function __construct() {
var_dump(property_exists($this, 'foo'));
var_dump(property_exists($this, 'goo'));
var_dump(property_exists($this, 'poo'));
check_scope($this);
parent::__construct();
}
}
class c extends b {
private $poo;
public function __construct() {
var_dump(property_exists($this, 'foo'));
var_dump(property_exists($this, 'goo'));
var_dump(property_exists($this, 'poo'));
check_scope($this);
parent::__construct();
}
}
new c();
Expected result:
----------------
Given the accessibility consideration I would expect property_exists to return true in all of the
cases outlined in the test script. However, running the script will show that property existence
checks depend on both the location of the private variable definition AND the location of the
property_exists method call. The results in the check_scope() method do not match the results of
the same logic copy and pasted into each constructor method.
Actual result:
--------------
bool(false)
bool(false)
bool(true)
vs
bool(false)
bool(false)
bool(true)
bool(false)
bool(true)
bool(true)
vs
bool(false)
bool(false)
bool(true)
bool(true)
bool(false)
bool(true)
vs
bool(false)
bool(false)
bool(true)
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=66670&edit=1