Bug #64497 [Opn->Wfx]: ReflectionProperty::setValue triggers __set for unset property

From: Date: Sat, 29 Sep 2018 17:04:59 +0000
Subject: Bug #64497 [Opn->Wfx]: ReflectionProperty::setValue triggers __set for unset property
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-217287@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=64497&edit=1 ID: 64497 Updated by: nikic@php.net Reported by: me at fixxxer dot me Summary: ReflectionProperty::setValue triggers __set for unset property -Status: Open +Status: Wont fix Type: Bug Package: Reflection related Operating System: any PHP Version: 5.4Git-2013-03-23 (snap) Block user comment: N Private report: N New Comment: The current consensus on the topic of unsetting declared properties is that, while somewhat weird, this is the behavior we want to have. The behavior is used to implement lazy initialization by unsetting a declared property and initializing it in __get. Reflection getValue() and setValue() methods are (essentially) equivalent to just performing the respective property reads/writes, so they will behave the same way, including potential calls to magic methods and undefined property notices. In PHP 7.4, as part of the typed properties proposal, there will be a new ReflectionProperty::isInitialized() method which allows to check whether a property is unset. Previous Comments: ------------------------------------------------------------------------ [2017-09-29 07:48:10] pierre dot rineau at makina-corpus dot com Sorry: "but when as a developper I write a statically defined class, it should NOT be modifiable by runtime" ------------------------------------------------------------------------ [2017-09-29 07:46:52] pierre dot rineau at makina-corpus dot com > I do understand why unset properties aren't completely removed from an object: > it's required to preserve the visibility scope. But it believe it should be > completely hidden from "outer world", and should not be exposed to > property_exists, Reflection or whatever. If property is defined as a class property, it should not be unset() but only initialized to null. Removing the property existence from the outside world makes the statically typed class change hence it becomes more similar to python and javascript monkey patching than it is from statically typed and defined language. I know that PHP is fundamentally dynamic, but when as a developper I write a statically defined class, it should be modifiable by runtime, else it will trigger undefined or side effect behaviours that cannot exist per language definition. ------------------------------------------------------------------------ [2017-09-28 14:51:58] cmb@php.net Related To: Bug #72194 ------------------------------------------------------------------------ [2013-03-23 23:13:32] me at fixxxer dot me Some more thoughts on this issue. Existence of unset() property is weird by itself. I do understand why unset properties aren't completely removed from an object: it's required to preserve the visibility scope. But it believe it should be completely hidden from "outer world", and should not be exposed to property_exists, Reflection or whatever. ------------------------------------------------------------------------ [2013-03-23 22:45:41] me at fixxxer dot me Description: ------------ I'm not sure it's a bug. And if it is, it's a low priority bug. But current behavior is illogical: ReflectionProperty represents an existing property, and it is logical to assume it never triggers magic methods. The case is a bit weird. :) We've had a discussion on phpclub.ru forums (in Russian, http://phpclub.ru/talk/threads/75432/page-2) about dealing with the case when a property has been unset() and there are magic methods present. When you unset a property, it is visible as undefined ("Undefined property" notice), and if there is a __set method, it starts being triggered when setting te same property. But property_exists() returns true for this property, so it means the property is still there in internal object structures - it is not the same as it has never been defined. During the discussion on restoring the property without triggering __set, I came up with an idea to use ReflectionProperty. But it ended up with a strange result shown in the test script. My point is that ReflectionProperty::setValue should never trigger __set. Test script: --------------- class C { protected $foo; public function test() { var_dump('Setting value with ReflectionProperty::setValue...'); $foo = (new ReflectionClass($this))->getProperty('foo'); $foo->setAccessible(true); $foo->setValue($this, 'foo'); // sets value, ok $foo->setAccessible(false); var_dump($this->foo); var_dump('Unsetting...'); unset($this->foo); var_dump($this->foo); var_dump('Setting value with ReflectionProperty::setValue again...'); $foo = (new ReflectionClass($this))->getProperty('foo'); $foo->setAccessible(true); $foo->setValue($this, 'foo'); // triggers __set() ! $foo->setAccessible(false); var_dump($this->foo); } public function __set($k, $v) { var_dump("__set triggered: [$k] = '$v'"); } } (new C)->test(); Expected result: ---------------- string(50) "Setting value with ReflectionProperty::setValue..." string(3) "foo" string(12) "Unsetting..." Notice: Undefined property: C::$foo in /home/build/tmp/1.php on line 20 NULL string(56) "Setting value with ReflectionProperty::setValue again..." string(3) "foo" Actual result: -------------- string(50) "Setting value with ReflectionProperty::setValue..." string(3) "foo" string(12) "Unsetting..." Notice: Undefined property: C::$foo in /home/build/tmp/1.php on line 20 NULL string(56) "Setting value with ReflectionProperty::setValue again..." string(30) "__set triggered: [foo] = 'foo'" Notice: Undefined property: C::$foo in /home/build/tmp/1.php on line 28 NULL ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=64497&edit=1

« previous php.bugs (#217287) next »