|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72174 ReflectionProperty#getValue() causes __isset call
Submitted: 2016-05-07 18:24 UTC Modified: 2016-05-12 15:40 UTC
From: ocramius at gmail dot com Assigned: nikic
Status: Closed Package: Reflection related
PHP Version: 7.0.6 OS:
Private report: No CVE-ID:
 [2016-05-07 18:24 UTC] ocramius at gmail dot com
When using `ReflectionProperty#getValue($object)` on a `$object` with an `unset()` property and defined `__isset` and `__get` methods, the `__get` method is called, while it should only use `__get`.

Note that this is a bug that affects only PHP 7.0.6, and isn't part of 7.0.5.

Test script:

class Foo
    private $bar;

    public function __construct()

    public function __isset($name)

        return true;
    public function __get($name)

        return $name;

$instance = new Foo();

$reflectionBar = (new ReflectionProperty(Foo::class, 'bar'));
$closureBar = (function (Foo $instance) {
    return $instance->bar;
})->bindTo(null, Foo::class);


Expected result:
string(10) "Foo::__get"
string(3) "bar"
string(10) "Foo::__get"
string(3) "bar"

Actual result:
string(12) "Foo::__isset"
string(10) "Foo::__get"
string(3) "bar"
string(10) "Foo::__get"
string(3) "bar"


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2016-05-07 18:25 UTC] ocramius at gmail dot com
 [2016-05-07 18:27 UTC] ocramius at gmail dot com
Note: bug was discovered in builds of ProxyManager at
 [2016-05-07 18:48 UTC] ocramius at gmail dot com
Bug seems to really only affect reflection access:
 [2016-05-07 18:59 UTC]
To summarize OTR discussion:

The issue is that ReflectionProperty::getValue() currently performs a "silenced read", which is roughly equivalent to doing isset($obj->prop) ? $obj->prop : NULL. Prior to PHP 7.0.6 the isset($obj->prop) part did not result in a call to __isset() due to a bug in the magic method implementation.

However, it can be be argued that ReflectionProperty::getValue() should not be performing a silenced read in the first place. It should simply return the value of $obj->prop. If we make this change then the behavior described in the bug report will go back to what it was. On the other hand, this means that using ReflectionProperty::getValue() to read an undefined property will throw an undefined property notice (currently suppressed:

The current plan is to change ReflectionProperty::getValue() to perform the read without silencing.
 [2016-05-07 19:00 UTC] ocramius at gmail dot com
As per discussion with NikiC and bwoebi in

There has been an ever-living bug in `ReflectionProperty#getValue()` that causes the reflection property to be read (and return `NULL`) even when not set, and that without causing a warning. That can be seen at

Code below as reference:


class Foo
    public $bar;

$instance = new Foo;


var_dump((new ReflectionProperty(Foo::class, 'bar'))->getValue($instance));

This code always returns `NULL`, but it should raise a NOTICE.

PHP 7.0.6 somehow mitigates the bug by doing an implicit `isset()` check internally, but that changes behavior of `ReflectionProperty#getValue()` in such a way that it breaks some userland existing code ( - possibly also other codebases) by causing `__isset` calls.

Making `ReflectionProperty#getValue()` trigger a notice when a property IS_UNDEF could probably be a good solution.
 [2016-05-10 10:18 UTC]
Automatic comment on behalf of nikic
Log: Fixed bug #72174
 [2016-05-10 10:18 UTC]
-Status: Open +Status: Closed
 [2016-05-10 14:14 UTC] ocramius at gmail dot com
Looks good from here! Related tests seem to pass on 7.0.7-DEV

 [2016-05-12 11:33 UTC]
-Assigned To: +Assigned To: mbeccati
 [2016-05-12 11:33 UTC]
it's actually a weird coincidence that it was you who submitted the bug. The fix is actually causing a regression in Doctrine now:


object(ReflectionProperty)#201 (2) {
  string(7) "country"
  string(33) "Doctrine\Tests\Models\Cache\State"

and getValue() is called with a Doctrine\Tests\Models\Cache\City entity.

PHP 5.6 doesn't complain, whereas PHP-7.0 current does:

"Undefined property: Doctrine\Tests\Models\Cache\City::$country"

I'll leave it up to you guys to decide what to do ;)
 [2016-05-12 11:34 UTC]
-Assigned To: mbeccati +Assigned To: nikic
 [2016-05-12 15:12 UTC] ocramius at gmail dot com
Saw that failure in my mailbox, thought it was unrelated.

As far as I can remember, doctrine only unsets `public` properties and uses a reflection workaround to access them (, so something else is going on there.

I'll test against the latest PHP-7.0 ASAP
 [2016-05-12 15:25 UTC] ocramius at gmail dot com
@mbeccati this seems to be a failure on doctrine's side. I traced it down, and it seems like:

 * `Doctrine\Tests\Models\Cache\City#$state` is not defined (property doesn't exist)
 * `new ReflectionProperty(\Doctrine\Tests\Models\Cache\State::class, 'country')` is used as reflection property (wrong class)
 * PHP doesn't seem to check that the instance passed to `getValue()` respects the original interface ( see ), and that causes the code to fail with a notice rather than with something like a `ReflectionException`

I will open a new issue about this.
 [2016-05-12 15:39 UTC] ocramius at gmail dot com
Findings moved to
 [2016-05-12 15:40 UTC] ocramius at gmail dot com
Closing, moved remaining bits to
 [2016-07-20 11:31 UTC]
Automatic comment on behalf of nikic
Log: Fixed bug #72174
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue Feb 21 14:01:44 2017 UTC