webentwicklung-frage-antwort-db.com.de

"Indirekte Änderung eines überladenen Elements von SplFixedArray hat keine Auswirkung"

Warum das Folgende?

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

produziert

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

Ist es ein Fehler? Wie gehen Sie dann mit multidimensionalen SplFixedArrays um? Irgendwelche Problemumgehungen?

24
Desmond Hume

Erstens bezieht sich das Problem auf alle Klassen, die ArrayAccess implementieren. Es handelt sich nicht nur um ein spezielles Problem von SplFixedArray.


Wenn Sie mit dem []-Operator auf Elemente aus SplFixedArray zugreifen, verhält es sich nicht genau wie ein Array. Intern wird die offsetGet()-Methode aufgerufen, und in Ihrem Fall wird ein Array - zurückgegeben, jedoch kein Verweis auf dieses Array. Dies bedeutet, dass alle Änderungen, die Sie an $a[0] vornehmen, verloren gehen, sofern Sie sie nicht zurückspeichern:

Problemumgehung:

$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);

Hier ist ein Beispiel, das einen Skalar verwendet das ebenfalls fehlschlägt - um nur zu zeigen, dass es sich nicht nur um Array-Elemente handelt.

38
hek2mgl

Dies ist tatsächlich fixierbar, wenn Sie einen & vor offsetGet setzen (vorausgesetzt, Sie haben Zugriff auf die internen Komponenten Ihrer ArrayAccess-Implementierung):

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)]);
    }
}
4
mpen

Meine Erfahrung mit dem gleichen Fehler hinzufügen, falls es jemandem hilft:

Ich habe meinen Code kürzlich in ein Framework mit niedriger Fehlertoleranz (Laravel) importiert. Daher gibt mein Code jetzt eine Ausnahme aus, wenn ich versuche, einen Wert aus einem assoziativen Array mit einem nicht vorhandenen Schlüssel abzurufen. Um dies zu bewältigen, habe ich versucht, mein eigenes Wörterbuch mit der ArrayAccess-Schnittstelle zu implementieren. Das funktioniert gut, aber die folgende Syntax schlägt fehl:

$myDict = new Dictionary();
$myDict[] = 123;
$myDict[] = 456;

Und im Falle einer Multimap:

$properties = new Dictionary();
$properties['colours'] = new Dictionary();
$properties['colours'][] = 'red';
$properties['colours'][] = 'blue';

Ich konnte das Problem mit der folgenden Implementierung beheben:

<?php

use ArrayAccess;

/**
 * Class Dictionary
 *
 * DOES NOT THROW EXCEPTIONS, RETURNS NULL IF KEY IS EMPTY
 *
 * @package fnxProdCrawler
 */
class Dictionary implements ArrayAccess
{
    // FOR MORE INFO SEE: http://alanstorm.com/php_array_access

    protected $dict;

    function __construct()
    {
        $this->dict = [];
    }

    // INTERFACE IMPLEMENTATION - ArrayAccess
    public function offsetExists($key)
    {
        return array_key_exists($key, $this->dict);
    }
    public function offsetGet($key)
    {
        if ($this->offsetExists($key))
            return $this->dict[$key];
        else
            return null;
    }
    public function offsetSet($key, $value)
    {
        // NOTE: THIS IS THE FIX FOR THE ISSUE "Indirect modification of overloaded element of SplFixedArray has no effect"
        // NOTE: WHEN APPENDING AN ARRAY (E.G. myArr[] = 5) THE KEY IS NULL, SO WE TEST FOR THIS CONDITION BELOW, AND VOILA

        if (is_null($key))
        {
            $this->dict[] = $value;
        }
        else
        {
            $this->dict[$key] = $value;
        }
    }
    public function offsetUnset($key)
    {
        unset($this->dict[$key]);
    }
}

Ich hoffe es hilft.

0
mils