|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2007-06-08 22:50 UTC] asnyder at mddev dot com
Description:
------------
Ok, the bug is as follows. If one gets an array, via the __get, and then continues to modify the subobject properties using a __set. It will call the __set function, but throw the
Notice: Indirect modification of overloaded property A::$Test has no effect in /var/www/html/Tests/PHPBug.php on line 43
In PHP 5.1.2 this process worked fine, but in 5.2.3 it causes the notice.
Reproduce code:
---------------
class A
{
private $Test = array("One" => null, 'Two' => null);
function A()
{
$this->Test['One'] = new B();
}
function __get($val)
{
return $this->Test;
}
}
class B
{
private $SomeVariable;
function GetSomething(){return $this->SomeVariable;}
function SetSomething($bool)
{
$this->SomeVariable = $bool;
}
function __get($val)
{
$this->GetSomething();
}
function __set($part, $val)
{
$this->SetSomething($val);
}
}
$tmpA = new A();
// Now in PHP 5.1.2 the following code works, in PHP 5.2.3 but throws the notice Indirect modification of overloaded property
$tmpA->Test['One']->Something = true;
//In PHP 5.2.3 one would have to do the following for the notice not to throw. Which is not the expected behavior
//$tmpA->Test['One']->SetSomething(true);
Expected result:
----------------
The SetSomething($val) function should be called, and it IS being called, but with throwing a notice. It should behave like in 5.1.2 and run the SetSomething($val) function without the notice.
One should NOT have to call $tmpA->Test['One']->SetSomething(true) to not raise the notice.
Actual result:
--------------
Calls function and throws notice.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 03:00:01 2025 UTC |
It seems that declaring the getter as "public function &__get(){...}" does the trick. However, it took some googling to find.brjann: well, you're right, it will work if you use "public function &__get(){...}". But that solution will not call __set at all (which is a problem in some cases). the following example won't throw a warning and will basically work: <?php error_reporting(E_ALL); class newclass { private $properties; public function &__get($key) { echo "get $key<br>"; return $this->properties[$key]; } public function __set($key, $val) { echo "set $key to $val<br>"; $this->properties[$key] = $val; } } $c = new newclass; $c->array['test'] = 'test'; ?> expected output: get array set array to test actual output: get array I understand that it's not possible to catch this modification because it's done via reference, so i won't write a bugreport... Although it's still a bit confusing...First, a much simpler test case: class foo { private $bar = array(); public function __construct() { $this->bar[0] = new stdClass; $this->bar[0]->five = 5; } public function __get($n) { return $this->bar; } } $foo = new foo; $foo->bar[0]->seventeen = 17; var_dump($foo); * * * Of course, this produces: object(foo)#1 (1) { ["bar":"foo":private]=> array(1) { [0]=> object(stdClass)#2 (2) { ["five"]=> int(5) ["seventeen"]=> int(17) } } } But also generates the warning. The warning is certainly useful for informing users that they are not actually modifying the array index inside the class when using non-objects, but since all objects are considered to be passed by reference this warning is indeed quite bogus, and breaks formatted responses (e.g. from a web service). Furthermore, using a by-reference declaration for __get is a horse of a different color, as I am passing entire properties by reference, and if I'm going to do that I might as well just make them public to begin with and circumvent the performance hit incurred with __get. However, there is a reason these properties are private with __get pseudo- access, so either of these solutions is less than ideal. Simply put, this notice only occurs when an array index fetched via __get is used in conjunction with some type of assignment, so would it be so difficult to check, before generating this notice, whether the value at that array index is, in fact, a reference? Fun side node, if you nest objects you can get multiple notices. Assuming the class declaration from above: $foo = new foo; $foo->bar[0]->baz = new foo; // generates one notice $foo->bar[0]->baz->bar[0]->eleven = 11; // generates two notices That code will generate 3 notices altogether, and yet the object structure will look *exactly* how one would expect it to look. Ironically, one could circumvent all of this by using an object instead of an array -- except that objects don't support numerical member names, or even access without some massaging, which can even end you up back in square one with nothing but wasted time to show for it.