ArrayObject no funciona con end () en PHP 7.4

9

Al migrar a PHP 7.4 tengo que lidiar con un comportamiento diferente de algunas funciones de matriz como reset(), current()o con end()respecto a ArrayObject. El siguiente ejemplo produce diferentes salidas:

<?php

$array = new \ArrayObject(["a", "b"]);
$item = end($array);
var_dump($item);


$array = ["a", "b"];
$item = end($array);
var_dump($item);

Con php 7.4 el resultado es:

bool(false)
string(1) "b"

En las versiones de PHP anteriores a 7.4, el resultado es el siguiente:

string(1) "b"
string(1) "b"

A end($array->getArrayCopy())produce un aviso, pero podría ser una solución si se usa con una variable.

¿Hay alguna manera de emular el comportamiento de end()con un ArrayObjecto ArrayIterator? El ArrayObject podría ser muy grande, una iteración hasta el final podría no ser la mejor solución.

Trendfischer
fuente
Una alternativa podría ser $item = $array[count($array)-1];. No estoy seguro si esa es la solución más eficiente.
Patrick Q
2
Yo diría que califica como un error de PHP, definitivamente hay nada en la lista de cambios que sugiere esto fue un cambio previsto en el apartado 7.4
iainn
Pruébelo
0stone0
1
@PatrickQ ¿y si es asociativo?
Andreas
44
@iainn esto definitivamente no es un error - php.net/manual/en/…
u_mulder

Respuestas:

2

Desde PHP 7.4, los métodos de matriz no operan en una matriz interna, sino en ArrayObjectsí misma. Resumí dos soluciones para eso.

1. Obtener una matriz interna de objetos.

$array = new \ArrayObject(["a", "b"]);
$item = end($array->getArrayCopy());

2. Crear Fachada de ArrayObjecty agregar método personalizado end () a la clase actualizada.

Tajniak
fuente
0

Puede convertir el objeto de matriz en una matriz para obtener las claves y luego usar end en las claves para obtener la última clave.

$array = new \ArrayObject(["a", "b"]);
$keys = array_keys((array)$array);
$end_key = end($keys);

var_dump($array[$end_key]);

No es una solución bonita pero funciona.
Le sugiero que lo convierta en una función para que pueda llamarlo cuando sea necesario.

https://3v4l.org/HTGYn

Como una función:

function end_object($array){
    $keys = array_keys((array)$array);
    $end_key = end($keys);
    return $array[$end_key];
}


$array = new \ArrayObject(["a", "b"]);
$item = end_object($array);
var_dump($item);
Andreas
fuente
No veo diferencia entre ambas respuestas cuando miro el resultado y usaqe en cuestión. si la diferencia explica por favor
Dlk
1
He probado la array_keys()solución con 3v4l.org/IaEMM/perf#output pero necesitaba un 20-30% más de memoria en comparación con un end()simple getArrayCopy() 3v4l.org/uYv59/perf#output
Trendfischer
1
@Trendfischer Si el problema es la memoria y si solo desea usarla end, puede crear una clase de contenedor que implemente ArrayAccessy tenga una función adicional que devuelva una endde la matriz privada interna que se operaría.
vivek_23
1
@ vivek_23 suena como una buena respuesta
Trendfischer
3
Pregunta: ¿para qué sirve array_keys? ¿Por qué no lo lanzas directamente $arr = (array) $arrayy luego$end = end($arr)
Lluvia
0

Un enfoque un poco más rápido sin convertir o usar un iterador sería no usar el constructor en primer lugar, y en su lugar usar un appendmétodo que creará una matriz en sí misma y que puede usar enden esa matriz más tarde

$array = new \ArrayObject();
$array->append(["a", "b"]);
$item =  end($array[count($array) - 1]);
var_dump($item);

count($array) - 1en caso de que agregue otra matriz más tarde, nos aseguramos de que $itemsiempre sea el último elemento en la última matriz agregada.

Lluvia
fuente
1
Gracias, la solución count()podría ser útil en algunos casos, pero su ejemplo no funcionaría para algo como estonew \ArrayObject([123 => "a", 456 => "c"]);
Trendfischer
@Trendfischer Sé que es por eso que utilicé en appendlugar del constructor, usar append con tu ejemplo definitivamente funcionará. $array->append([123 => "a", 456 => "c"]
Lluvia
@Trendfischer Tenga en cuenta countque no es para los elementos de su matriz, es para la matriz multidimensional que appendcreará. Para su matriz estamos utilizando endcomo de costumbre.
Lluvia
1
Aprecio la intención, pero generalmente no uso un ArrayObject como un simple reemplazo para una matriz. El ejemplo en la pregunta es ejemplar para mostrar el problema. Aunque si solo uso append(), podría usar una count()solución válida. Eso podría funcionar con append('a')y append('b'). La clave sería no permitir matrices asociativas, que es una posibilidad al extender ArrayObject.
Trendfischer