"Indirect modification of overloaded element of SplFixedArray has no effect"

32,101

Solution 1

First, the problem is related to all classes which implement ArrayAccess it is not a special problem of SplFixedArray only.


When you accessing elements from SplFixedArray using the [] operator it behaves not exactly like an array. Internally it's offsetGet() method is called, and will return in your case an array - but not a reference to that array. This means all modifications you make on $a[0] will get lost unless you save it back:

Workaround:

$a = new SplFixedArray(5);
$a[0] = array(1, 2, 3); 
// get element
$element = $a[0];
// modify it
$element[0] = 12345;
// store the element again
$a[0] = $element;

var_dump($a);

Here is an example using a scalar which fails too - just to show you that it is not related to array elements only.

Solution 2

This is actually fixable if you slap a & in front of offsetGet (assuming you have access to the internals of your ArrayAccess implementation):

class Dict implements IDict {
    private $_data = [];

    /**
     * @param mixed $offset
     * @return bool
     */
    public function offsetExists($offset) {
        return array_key_exists(self::hash($offset), $this->_data);
    }

    /**
     * @param mixed $offset
     * @return mixed
     */
    public function &offsetGet($offset) {
        return $this->_data[self::hash($offset)];
    }

    /**
     * @param mixed $var
     * @return string
     */
    private static function hash($var) {
        return is_object($var) ? spl_object_hash($var) : json_encode($var,JSON_UNESCAPED_SLASHES);
    }

    /**
     * @param mixed $offset
     * @param mixed $value
     */
    public function offsetSet($offset, $value) {
        $this->_data[self::hash($offset)] = $value;
    }

    /**
     * @param mixed $offset
     */
    public function offsetUnset($offset) {
        unset($this->_data[self::hash($offset)]);
    }
}
Share:
32,101
Desmond Hume
Author by

Desmond Hume

Updated on November 16, 2020

Comments

  • Desmond Hume
    Desmond Hume over 3 years

    Why the following

    $a = new SplFixedArray(5);
    $a[0] = array(1, 2, 3);
    $a[0][0] = 12345; // here
    var_dump($a);
    

    produces

    Notice: Indirect modification of overloaded element of SplFixedArray has no effect in <file> on line <indicated>
    

    Is it a bug? How do you deal with multidimensional SplFixedArrays then? Any workarounds?