ArrayObject nie działa z end () w PHP 7.4

9

Dotyczące migracji do PHP 7.4 mam do czynienia z innym zachowaniem pewnych funkcji, takich jak tablicy reset(), current()lub end()dotycząca ArrayObject. Poniższy przykład przedstawia różne wyniki:

<?php

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


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

W przypadku php 7.4 wynikiem jest:

bool(false)
string(1) "b"

W wersjach PHP wcześniejszych niż 7.4 wyniki są następujące:

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

A end($array->getArrayCopy())generuje powiadomienie, ale może być obejściem, jeśli jest używane ze zmienną.

Czy istnieje sposób naśladowania zachowania end()za pomocą ArrayObjectlub ArrayIterator? ArrayObject może być bardzo duży, iteracja do końca może nie być najlepszym rozwiązaniem.

Trendfischer
źródło
Alternatywą może być $item = $array[count($array)-1];. Nie jestem pewien, czy jest to najbardziej wydajne rozwiązanie.
Patrick Q
2
Powiedziałbym, że kwalifikuje się to jako błąd PHP, zdecydowanie nie ma w
dzienniku
Przetestuj online: 3v4l.org/4MADI
0stone0
1
@PatrickQ co jeśli jest to skojarzenie?
Andreas
4
@iainn to zdecydowanie nie jest błąd - php.net/manual/en/…
u_mulder

Odpowiedzi:

2

Z PHP 7.4 metody tablicowe nie działają na wewnętrznej tablicy, ale na ArrayObjectsamej sobie. Podsumowałem dwa rozwiązania.

1. Uzyskiwanie wewnętrznej tablicy obiektów.

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

2. Tworzenie fasady ArrayObjecti dodawanie niestandardowej metody end () do ulepszonej klasy.

Tajni
źródło
0

Możesz ustawić obiekt tablicowy jako tablicę, aby uzyskać klucze, a następnie użyć klawisza end na klawiszach, aby uzyskać ostatni klucz.

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

var_dump($array[$end_key]);

To nie jest ładne rozwiązanie, ale działa.
Sugeruję, aby uczynić to funkcją, aby można było wywoływać ją w razie potrzeby.

https://3v4l.org/HTGYn

Jako funkcja:

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
źródło
Nie widzę różnicy między obiema odpowiedziami, gdy patrzę na wynik, a pytaniem o USAqe. jeśli różnica wyjaśnić proszę
Dlk
1
Testowałem array_keys()rozwiązanie z 3v4l.org/IaEMM/perf#output, ale wymagało 20-30% więcej pamięci w porównaniu z end()prostym getArrayCopy() 3v4l.org/uYv59/perf#output
Trendfischer
1
@Trendfischer Jeśli problemem jest pamięć i jeśli chcesz endtylko używać , możesz utworzyć klasę opakowania, która implementuje ArrayAccessi ma dodatkową funkcję, która zwraca endwewnętrzną prywatną tablicę, która byłaby obsługiwana.
vivek_23
1
@ vivek_23 brzmi jak dobra odpowiedź
Trendfischer
3
Pytanie: jaki jest cel array_keys? dlaczego nie rzucisz go bezpośrednio, $arr = (array) $arraya potem$end = end($arr)
Rain
0

Nieco szybszym podejściem bez rzucania lub używania iteratora byłoby nieużywanie konstruktora, a zamiast tego append metody, która utworzy samą tablicę i można z niej korzystać endpóźniej

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

count($array) - 1w przypadku, gdy później dodasz kolejną tablicę, upewniamy się, że $itemjest to zawsze ostatni element w ostatniej dołączonej tablicy.

Deszcz
źródło
1
Dzięki, rozwiązanie z count()może być pomocne w niektórych przypadkach, ale twój przykład nie działałby dla czegoś takiegonew \ArrayObject([123 => "a", 456 => "c"]);
Trendfischer
@Trendfischer Wiem, że dlatego użyłem appendzamiast konstruktora, użycie append z twoim przykładem na pewno zadziała. $array->append([123 => "a", 456 => "c"]
Deszcz
@Trendfischer Należy pamiętać, że countnie dotyczy elementów tablicy, lecz wielowymiarowej tablicy, appendktóra utworzy. Do twojej tablicy używamy endjak zwykle.
Deszcz
1
Doceniam ten zamiar, ale zwykle nie używam ArrayObject jako prostego zamiennika tablicy. Przykład w pytaniu jest przykładowy, aby pokazać problem. Chociaż gdybym tylko użył append(), mógłbym użyć count(), to jest prawidłowe rozwiązanie. To może działać z append('a')i append('b'). Kluczem byłoby wyłączenie tablic asocjacyjnych, co jest możliwe poprzez rozszerzenie ArrayObject.
Trendfischer