valores valor primer obtener modificar manejo functions extraer elemento datos comparar buscar array php arrays spl

php - valor - “La modificación indirecta del elemento sobrecargado de SplFixedArray no tiene efecto”



obtener el valor de un array php (4)

Agregando mi experiencia con el mismo error, en caso de que ayude a alguien:

Recientemente importé mi código a un marco con una baja tolerancia a errores (Laravel). Como resultado, mi código ahora lanza una excepción cuando trato de recuperar un valor de una matriz asociativa usando una clave inexistente. Para lidiar con esto, intenté implementar mi propio diccionario usando la interfaz ArrayAccess. Esto funciona bien, pero la siguiente sintaxis falla:

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

Y en el caso de un multimap:

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

Logré solucionar el problema con la siguiente implementación:

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

Espero eso ayude.

¿Por qué lo siguiente?

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

produce

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

¿Es un error? ¿Cómo tratas con SplFixedArrays multidimensional entonces? ¿Alguna solución?


Esto es realmente solucionable si se opone a & delante de offsetGet (asumiendo que tiene acceso a las ArrayAccess internas de su implementación ArrayAccess ):

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


Primero, el problema está relacionado con todas las clases que implementan ArrayAccess no es un problema especial de SplFixedArray solamente.

Cuando accede a elementos de SplFixedArray utilizando el operador [] , no se comporta exactamente como una matriz. Internamente, se offsetGet() método offsetGet() y, en su caso, devolverá una matriz, pero no una referencia a esa matriz. Esto significa que todas las modificaciones que realice en $a[0] se perderán a menos que las guarde de nuevo:

Solución:

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

Aquí hay un ejemplo que usa un escalar que también falla, solo para mostrarle que no está relacionado solo con elementos de la matriz.


Supongo que SplFixedArray está incompleto / con errores.

Si escribí una clase propia y funciona como un encanto:

$a = new /myArrayClass(); $a[0] = array(1, 2, 3); $a[0][0] = 12345; var_dump($a->toArray());

Salida (no hay avisos / advertencias aquí, también en modo estricto):

array (size=1) 0 => array (size=3) 0 => int 12345 1 => int 2 2 => int 3

El uso del operador [] no es un problema (también para arreglos assoc / mixtos). Una implementación correcta de offsetSet debe hacer el trabajo:

public function offsetSet($offset, $value) { if ($offset === null) { $offset = 0; if (/count($this->array)) { $keys = /preg_grep( ''#^(0|([1-9][0-9]*))$#'', /array_keys($this->array)); if (/count($keys)) { $offset = /max($keys) + 1; } } } ...

Pero solo hay una excepción. No es posible utilizar el operador [] para el desplazamiento que no existe. En nuestro ejemplo:

$a[1][] =''value''; // Notice: Indirect modification of overloaded...

Arrojaría la advertencia anterior porque ArrayAccess llama a offsetGet y no a offsetSet para [1] y la última [] falla. Tal vez haya una solución, pero no la encontré todavía. Pero lo siguiente está funcionando sin problemas:

$a[] =''value''; $a[0][] =''value'';

Escribiría una implementación propia en lugar de usar SplFixedArray. Tal vez es posible sobrecargar algunos métodos en SplFixedArray para solucionarlo, pero no estoy seguro porque nunca usé y verifiqué SplFixedArray.