ArrayObject ne fonctionne pas avec end () en PHP 7.4

9

Lors de la migration vers PHP 7.4, je dois faire face à un comportement différent de certaines fonctions de tableau comme reset(), current()ou end()concernant ArrayObject. L'exemple suivant produit différentes sorties:

<?php

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


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

Avec php 7.4, la sortie est:

bool(false)
string(1) "b"

Sur les versions PHP antérieures à 7.4, la sortie est la suivante:

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

A end($array->getArrayCopy())produit un avis, mais peut être une solution de contournement s'il est utilisé avec une variable.

Existe-t-il un moyen d'émuler le comportement de end()avec ArrayObjectou ArrayIterator? ArrayObject peut être très volumineux, une itération à la fin n'est peut-être pas la meilleure solution.

Trendfischer
la source
Une alternative pourrait être $item = $array[count($array)-1];. Je ne sais pas si c'est la solution la plus efficace.
Patrick Q
2
Je dirais que cela est considéré comme un bug PHP, il n'y a certainement rien dans le
journal des
Testez-le en ligne: 3v4l.org/4MADI
0stone0
1
@PatrickQ et si c'est associatif?
Andreas
4
@iainn ce n'est certainement pas un bug - php.net/manual/en/…
u_mulder

Réponses:

2

Depuis PHP 7.4 , les méthodes de tableau ne fonctionnent pas sur le tableau interne, mais sur ArrayObjectlui-même. J'ai résumé deux solutions pour cela.

1. Obtention d'un tableau d'objet interne.

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

2. Création de la façade ArrayObjectet ajout de la méthode personnalisée end () à la classe mise à niveau.

Tajniak
la source
0

Vous pouvez faire de arrayobject un tableau pour obtenir les clés, puis utiliser end sur les clés pour obtenir la dernière clé.

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

var_dump($array[$end_key]);

Ce n'est pas une jolie solution mais ça marche.
Je vous suggère d'en faire une fonction pour pouvoir l'appeler en cas de besoin.

https://3v4l.org/HTGYn

En tant que fonction:

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
la source
Je ne vois pas de différence entre les deux réponses quand je regarde le résultat et l'USAQE en question. si la différence explique s'il vous plaît
Dlk
1
J'ai testé la array_keys()solution avec 3v4l.org/IaEMM/perf#output mais elle avait besoin de 20-30% de plus en mémoire par rapport à end()un simple getArrayCopy() 3v4l.org/uYv59/perf#output
Trendfischer
1
@Trendfischer Si la mémoire est le problème et si vous souhaitez l'utiliser enduniquement, vous pouvez créer une classe wrapper qui implémente ArrayAccesset avoir une fonction supplémentaire qui renvoie un enddu tableau privé interne qui serait exploité.
vivek_23
1
@ vivek_23 sonne comme une bonne réponse
Trendfischer
3
Question: quel est le but de array_keys? pourquoi ne pas le lancer directement $arr = (array) $arrayet ensuite$end = end($arr)
Pluie
0

Une approche légèrement plus rapide sans transtypage ni utilisation d'un itérateur serait de ne pas utiliser le constructeur en premier lieu, et d'utiliser à la place une appendméthode qui créera un tableau lui-même et que vous pourrez utiliser endsur ce tableau plus tard.

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

count($array) - 1si vous ajoutez un autre tableau plus tard, nous nous assurons qu'il $items'agit toujours du dernier élément du dernier tableau ajouté.

Pluie
la source
1
Merci, la solution avec count()pourrait être utile dans certains cas, mais votre exemple ne fonctionnerait pas pour quelque chose comme çanew \ArrayObject([123 => "a", 456 => "c"]);
Trendfischer
@Trendfischer Je sais que c'est pourquoi j'ai utilisé à la appendplace du constructeur, utiliser append avec votre exemple fonctionnera certainement. $array->append([123 => "a", 456 => "c"]
Pluie le
@Trendfischer Veuillez noter que ce countn'est pas pour les éléments de votre tableau, c'est pour le tableau multidimensionnel qui appendva créer. Pour votre tableau, nous utilisons endcomme d'habitude.
Pluie le
1
J'apprécie l'intention, mais je n'utilise généralement pas un ArrayObject comme simple remplacement d'un tableau. L'exemple de la question est exemplaire pour montrer le problème. Bien que si j'utilise seulement append(), je pourrais utiliser un count(), c'est une solution valide. Cela pourrait fonctionner avec append('a')et append('b'). La clé serait de interdire les tableaux associatifs, ce qui est possible en étendant ArrayObject.
Trendfischer