Bug #64497 [Com]: ReflectionProperty::setValue triggers __set for unset property

From: Date: Fri, 29 Sep 2017 07:48:11 +0000
Subject: Bug #64497 [Com]: ReflectionProperty::setValue triggers __set for unset property
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-211446@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 Comment by: pierre dot rineau at makina-corpus dot com Reported by: me at fixxxer dot me Summary: ReflectionProperty::setValue triggers __set for unset property Status: Open 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: Sorry: "but when as a developper I write a statically defined class, it should NOT be modifiable by runtime" Previous Comments: ------------------------------------------------------------------------ [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 (#211446) next »