php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #52441 Arrays misbehaving with __set() and __get()
Submitted: 2010-07-26 01:19 UTC Modified: 2013-07-30 02:45 UTC
Votes:1
Avg. Score:1.0 ± 0.0
Reproduced:0 of 1 (0.0%)
From: bastard dot internets at gmail dot com Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 5.3.3 and 5.3.2 OS: WIN
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: bastard dot internets at gmail dot com
New email:
PHP Version: OS:

 

 [2010-07-26 01:19 UTC] bastard dot internets at gmail dot com
Description:
------------
Mixing __set(), __get(), and protected/private/overloaded properties that are arrays has unexpected, undocumented, and undesirable results.  A couple of bugs listed below.  One bug is similar to bug 33941, but the problem still persists and even more bugs have popped up.

Test script:
---------------
<?php
class A {
    protected $test_array = array('key' => 'test');
      
	function __get($prop) {
		if (!property_exists($this, $prop)) {
			$this->$prop = null; // just to create it if it didn't exist
			}
		return $this->$prop;
		}
		
    function __set($prop, $val) {
        $this->$prop = $val;
        }
    }

$a = new A();
$a->test_array[] = 'asdf';

?>

Expected result:
----------------
New key/value "0=>'asdf'" assigned to protected class property array '$test_array'.  If the property didn't yet exist and overloading is attempted, just create the new '$test_array' property as an array as intended.  Working with arrays in this manner should work exactly like with any other variable type.

Actual result:
--------------
Depending on how the above test script is slightly tweaked, a few bugs pop up.  The focus here is on what happens with line "$a->test_array[] = 'asdf';"


1) If $test_array did *not* previously exist, "Notice: Indirect modification of overloaded property A::$test_array has no effect in ...test.php on line 18".  This *should've* worked fine.

2) If __set() was *not* declared, "Notice: Indirect modification of overloaded property A::$test_array has no effect in ...test.php on line 18".  This *should've* resulted in fatal "cannot access protected property" error.

3) If $test_array did *not* previously exist and __get() was *not* declared, it will work fine.  __get() *should've* never factored in here, and $test_array *should've* updated even if already declared private/protected.

4) If __get() was *not* declared, "PHP Fatal error:  Cannot access protected property A::$test_array".   __get() *should've* never factored in here.  If the '[]' compound operator is what's causing this, then __get() should return a copy of the array with new or existing index if provided to be processed through __set() as expected.

5) If $test_array was public, it will work fine, bypassing __get() and __set() as intended.  No bug here.

6) If __get() was declared to return a reference to the property (ie function &__get($prop){}), it will work fine and bypass __set().  Not a bug, but this workaround may cause other problems if expecting to process updates through __set() or wanting just a copy of any other property returned by __get().

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-07-26 01:36 UTC] bastard dot internets at gmail dot com
Amendment to bug #3: __set() is bypassed completely, and new arrays can be freely created within objects if not already protected or private.  Only if directly setting the array itself (ie "$a->test_array = array();") will __set() be called.  But not when doing something like "a$->test_array[] = 'asdf';"
 [2010-07-26 01:39 UTC] bastard dot internets at gmail dot com
Der, that last comment was meant to be "Amendment to Result #3".  Ignore that auto-linked reference to "bug #3"
 [2010-07-26 01:50 UTC] bastard dot internets at gmail dot com
-PHP Version: Irrelevant +PHP Version: 5.3.3 and 5.3.2
 [2010-07-26 01:50 UTC] bastard dot internets at gmail dot com
PHP Version: These bugs are found in 5.3.3 and 5.3.2.  Unknown status in 5.2.
 [2010-10-03 18:57 UTC] + at ni-po dot com
Could you elaborate your second point? I couldn't understand that one.

Concerning all the other ones: Our sixth point is the solution. This is expected behavior. To modify an array property it must be returned by reference. There already have been several bugs on this topic and yet another one won't change anything ;)
 [2010-11-12 20:15 UTC] bastard dot internets at gmail dot com
| Could you elaborate your second point? I couldn't understand that one.

When setting any private property from outside the object, you would normally expect to get a fatal "Cannot access private property" error.  However for private properties that are arrays, the line "$a->test_array[] = 'asdf'", where for all intents and purposes you are modifying a private property, just results in an odd notice.


| Concerning all the other ones: Our sixth point is the solution. This is expected behavior. To modify an array property it must be returned by reference. There already have been several bugs on this topic and yet another one won't change anything ;)

The problem with this solution ("&__get()") is that get() must always be defined to return by reference.  And, all other private/protected properties will have to be returned by reference as well (though I can't think of where this would be a serious problem off the top of my head).

The manual should at least be updated somewhere to mention that changes made to private/protected array properties from outside the object are routed through get(), not set(), and that the get() function must be defined to return the array property by reference.

Either that or have get() magically return array properties by reference by default..?
 [2011-09-11 22:28 UTC] jochen at menhir dot com
I have this bug too and there is not anything I can do about how ->property[0] = value is been done. 
What is the status on this for now?
 [2013-07-30 02:45 UTC] yohgaki@php.net
-Status: Open +Status: Not a bug
 [2013-07-30 02:45 UTC] yohgaki@php.net
__get/__set is not for array, but methods for property access.

If you would like to use object as array, use ArrayObject class.

http://www.php.net/manual/en/class.arrayobject.php
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 07:01:29 2024 UTC