Question

Example php code:

class TestArrayObject extends ArrayObject {
    function offsetSet($index,$val){
        echo $index.':'.$val.PHP_EOL;
    }
}

$s = new TestArrayObject();

//test 1
$s['a'] = 'value';//calls offsetSet
//test 2
$s['b']['c'] = 'value';//does not call offsetSet, why?

var_dump($s);

why doesn't test 2 call the offsetSet method?

Était-ce utile?

La solution

ArrayObject is a big chunk of magic and thus I wouldn't recommend using it or - even worse - extending it.

But your actual problem hasn't to do with ArrayObject by itself. What you are running into is that $s['b']['c'] = ...; is a so called indirect modification of the 'b' offset. The code that PHP executes for it looks roughly like this:

$offset =& $s['b'];
$offset['c'] = ...;

As you can see offset 'b' is never directly written to. Instead it is fetched by reference and the reference is modified. That's why offsetGet will be called, not offsetSet.

Autres conseils

For multidimensional arrays, see the user contributed notes here

This is kind of a "gotcha" since I think the expected behaviour would be as the OP stated in is question.

furthermore, the behaviour is not consistent when accessing the ArrayObject as an Object or as an Array.

Example:

$foo['b']['c'] = 'value'; // no warning
var_dump($foo);

$bar->b->c = 'value'; // triggers warning
var_dump($bar);

I was having the same trouble with my own class that extends ArrayObject. I wasn't able to fix the issue, but managed to work around it by implementing a new method that I use to chain property creation.

class Arraylist extends ArrayObject
{
    public function set($key, $value = null)
    {
        if (!is_null($value)) {
            $val = new ArrayList((array) $value);
        } else {
            $val = new ArrayList();
        }       
        $this->offsetSet($key, $val);
        return $this->offsetGet($key);
    }

    public function offsetSet($index,$val){
        echo $index.':'.$val.PHP_EOL;
        parent::offsetSet($index, $val);
    }
}

Using the OPs example:

Code:

$s = new ArrayList();
$s->set('a', 'value');
$s->set('b')->set('c', 'another value');
var_dump($s);

Outputs:

0:value
a:ArrayList
0:value
b:ArrayList
0:another value
c:ArrayList
0:another value

class ArrayList#5 (2) {
  public $a =>
  class ArrayList#7 (1) {
        string(5) "value"
  }
  public $b =>
  class ArrayList#8 (1) {
    public $c =>
    class ArrayList#9 (1) {
            string(13) "another value"
    }
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top