Bug #72177 [Com]: Scope issue in __destruct after ReflectionProperty::setValue()
Edit report at https://bugs.php.net/bug.php?id=72177&edit=1
ID: 72177
Comment by: ocramius at gmail dot com
Reported by: lbarnaud@php.net
Summary: Scope issue in __destruct after
ReflectionProperty::setValue()
Status: Assigned
Type: Bug
Package: Reflection related
PHP Version: 7.0Git-2016-05-09 (Git)
Assigned To: dmitry
Block user comment: N
Private report: N
New Comment:
Related: I got similar failures when accessing object state via __get, when
__get is triggered by reflection, as the scope with which __get is called
is wrong.
Specifically, something like following:
=====foo.php======
<?php
class Foo
{
private $bar = 'bar';
public function __construct()
{
unset($this->bar);
}
}
class Bar extends Foo
{
private $baz = 'baz';
private static $tab = 'tab';
public function __get(string $name)
{
var_dump($this->baz);
var_dump(self::$tab);
return $name;
}
}
$r = new ReflectionProperty(Foo::class, 'bar');
$r->setAccessible(true);
var_dump($r->getValue(new Bar));
=====/foo.php======
This will work in 7.0.0~7.0.7 (see https://3v4l.org/dQlsf), but
will crash on master (7.1.0-DEV), with something like following:
=====OUTPUT======
NULL
Fatal error: Uncaught Error: Cannot access private property Bar::$tab in foo.php:21
Stack trace:
#0 foo.php(20): Bar->__get('baz')
#1 [internal function]: Bar->__get('bar')
#2 foo.php(30): ReflectionProperty->getValue(Object(Bar))
#3 {main}
thrown in /Users/ocramius/Documents/Projects/ProxyManager/foo.php on line 21
=====/OUTPUT======
Previous Comments:
------------------------------------------------------------------------
[2016-05-12 21:23:56] nikic@php.net
Note that this affects not only __destruct(), but also __get() and other magic. E.g. the call https://github.com/Ocramius/ProxyManager/blob/6e15877fc03cc211ce798d497a21208a44f7b726/tests/ProxyManagerTest/Functional/LazyLoadingGhostFunctionalTest.php#L403
results in an access level error in https://gist.github.com/Ocramius/e4f481dd1d4f93adffb0646a780d1217#file-foo5731cbdb7cfb2968834795-php-L125.
------------------------------------------------------------------------
[2016-05-12 15:48:59] nikic@php.net
Fallout from the EG(scope) removal. Now EG(fake_scope) will continue shadowing the scope, even
though we might reenter a differently scoped method.
This looks a bit tricky... maybe we should just avoid the fake scoping altogether and add an extra
scope argument to the property handlers?
------------------------------------------------------------------------
[2016-05-09 13:28:50] lbarnaud@php.net
Description:
------------
When __destruct() is called, following a ReflectionProperty::setValue() call, scopes seem to be
wrong.
In the following reproducing script, the method Child::__destruct() fails to set
$this->bar to null, with the error Cannot access protected property
Child::$bar.
I can reproduce this in git master, but not in any version from 3v4l.org.
Test script:
---------------
<?php
class Child
{
protected $bar;
public function __destruct()
{
$this->bar = null;
}
}
class Parnt
{
protected $child;
public function doSomething()
{
$this->child = new Child();
$prop = new \ReflectionProperty($this, 'child');
$prop->setAccessible(true);
$prop->setValue($this, null);
}
}
$p = new Parnt();
$p->doSomething();
echo "OK\n";
Expected result:
----------------
OK
Actual result:
--------------
Fatal error: Uncaught Error: Cannot access protected property Child::$bar in /tmp/x.php:9
Stack trace:
#0 [internal function]: Child->__destruct()
#1 /tmp/x.php(23): ReflectionProperty->setValue(Object(Parnt), NULL)
#2 /tmp/x.php(28): Parnt->doSomething()
#3 {main}
thrown in /tmp/x.php on line 9
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=72177&edit=1
Thread (5 messages)