Bug #61945 [Com]: array returned from __get method gices a notice when trying to change a value
Edit report at https://bugs.php.net/bug.php?id=61945&edit=1
ID: 61945
Comment by: nikic@php.net
Reported by: sevenrow2 at yahoo dot com
Summary: array returned from __get method gices a notice when
trying to change a value
Status: Open
Type: Bug
Package: Dynamic loading
Operating System: Windows 7
PHP Version: 5.4.2
Block user comment: N
Private report: N
New Comment:
You should define __get to return by reference:
public function &__get($name) { ... }
Modifications of the type $foo->x[0] = 'y' (where ->x is a magic property) happen by
executing roughly the following code:
$array =& $foo->x;
$array[0] = 'y';
If $foo->x is not a reference here though, $array[0] = 'y' will only be able to change
the copied array, not the original one.
In your case you still see the change due to a lucky combination of arrays and objects. You
aren't actually modifying the array, but only the object and objects behave reference-like by
themselves.
---
I'd be inclined to close this as Not A Bug, but there is actually some kind of bug in here: PHP
should see that $foo->x[0]->y = 'z' does not change the returned array, so no notice
should appear. But I'm not sure whether that's fixable.
Previous Comments:
------------------------------------------------------------------------
[2012-05-04 22:33:22] sevenrow2 at yahoo dot com
Description:
------------
I'm using the latest downloadable version of PHP 5.4.2.
See the following code (this code works):
-----------
<?php
class A {
private $vars;
public function __get($name) {
if (!isset($this->vars[$name])) {
$arrObj = new B();
$this->vars[$name] = $arrObj;
}
$obj = $this->vars[$name];
return $obj;
}
}
class B {
public $rolename = 'foo';
}
$a = new A;
var_dump($a);
echo $a->role->rolename.PHP_EOL;
$a->role->rolename = 'test';
echo $a->role->rolename;
?>
-----------------
What happends in this code is that i create a simple object "A". From that object i try to
get the 'role' property. It doesn't exist, so the magic __get() function is called.
In there i create a B() object and i return the instance of that object. Right after that i'm
trying to access the 'rolename' property of the 'B()' object:
echo $a->role->rolename.PHP_EOL;
$a->role->rolename = 'test';
This works. It successfully echo's the rolename and changes it after that.
---------------------
The problem occurs when i return an array with objects:
<?php
class A {
private $vars;
public function __get($name) {
if (!isset($this->vars[$name])) {
$arrObj = array();
$arrObj[] = new B();
$arrObj[] = new B();
$this->vars[$name] = $arrObj;
}
return $this->vars[$name];
}
}
class B {
public $rolename = 'foo';
}
$a = new A;
var_dump($a);
echo $a->role[0]->rolename.PHP_EOL;
$a->role[0]->rolename = 'test';
echo $a->role[0]->rolename;
?>
------------------
This code gives me the following notice:
"Notice: Indirect modification of overloaded property A::$role has no effect"
Strangely enough it tells me that i can't change the property any more. Or better yet, it has
no effect. The only difference is, is that i get the object from an array.
The weird thing is though, that it DOES alter the value of the property, regardless of the notice.
I think the notice shouldn't be displayed in this case.
Test script:
---------------
<?php
class A {
private $vars;
public function __get($name) {
if (!isset($this->vars[$name])) {
$arrObj = array();
$arrObj[] = new B();
$arrObj[] = new B();
$this->vars[$name] = $arrObj;
}
return $this->vars[$name];
}
}
class B {
public $rolename = 'foo';
}
$a = new A;
var_dump($a);
echo $a->role[0]->rolename.PHP_EOL;
$a->role[0]->rolename = 'test';
echo $a->role[0]->rolename;
?>
Expected result:
----------------
I expected that $a->role[0]->rolename = 'test'; simply changed the value of that
property, but it generates an unexpected 'notice'.
But: echo $a->role[0]->rolename; does show me that the property was actually changed,
regardless of the notice which tells that it can't be changed.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=61945&edit=1
Thread (3 messages)