ArrayObject не работает с end () в PHP 7.4

9

На переходе к PHP 7.4 мне приходится иметь дело с различным поведением некоторых функций массива , как reset(), current()или end()относительно ArrayObject. Следующий пример производит разные выходные данные:

<?php

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


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

С php 7.4 на выходе получается:

bool(false)
string(1) "b"

В версиях PHP до 7.4 вывод выглядит следующим образом:

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

A end($array->getArrayCopy())создает уведомление, но может использоваться в качестве обходного пути, если используется с переменной.

Есть ли способ подражать поведению end()с ArrayObjectили ArrayIterator? ArrayObject может быть очень большим, итерация до конца может оказаться не лучшим решением.

Trendfischer
источник
Альтернатива может быть $item = $array[count($array)-1];. Не уверен, что это самое эффективное решение.
Патрик Q
2
Я бы сказал, что это квалифицируется как ошибка PHP, в
журнале
Протестируйте это онлайн: 3v4l.org/4MADI
0stone0
1
@PatrickQ, что если это ассоциативно?
Андреас
4
@iainn это, безусловно , не ошибка - php.net/manual/en/...
u_mulder

Ответы:

2

В PHP 7.4 методы массива работают не с внутренним массивом, а с ArrayObjectсамим собой. Я суммировал два решения для этого.

1. Получение внутреннего массива объекта.

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

2. Создание Фасада ArrayObjectи добавление пользовательского метода end () в обновленный класс.

Tajniak
источник
0

Вы можете сделать массивобъект массивом для получения ключей, затем использовать end для ключей, чтобы получить последний ключ.

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

var_dump($array[$end_key]);

Это не симпатичное решение, но оно работает.
Я предлагаю вам сделать это функцией, чтобы вы могли вызывать ее при необходимости.

https://3v4l.org/HTGYn

Как функция:

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
источник
Я не вижу разницы между обоими ответами, когда я смотрю на результат и используемое вопрос. если разница объясните пожалуйста
Dlk
1
Я протестировал array_keys()решение с 3v4l.org/IaEMM/perf#output, но ему потребовалось на 20-30% больше памяти, чем end()на простом getArrayCopy() 3v4l.org/uYv59/perf#output
Trendfischer
1
@Trendfischer Если проблема с памятью, и если вы хотите использовать endтолько ее, то вы можете создать класс-оболочку, который реализует ArrayAccessи имеет дополнительную функцию, которая возвращает endвнутренний закрытый массив, который будет работать.
vivek_23
1
@ vivek_23 звучит как хороший ответ
Trendfischer
3
Вопрос: какова цель array_keys? почему бы тебе просто не разыграть это прямо, $arr = (array) $arrayа затем$end = end($arr)
Дождь
0

Немного более быстрый подход без приведения или использования итератора состоял бы в том, чтобы вообще не использовать конструктор, а вместо этого использовать append метод, который создаст сам массив, и вы сможете использовать endэтот массив позже

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

count($array) - 1в случае, если вы добавите другой массив позже, мы гарантируем, что $itemэто всегда последний элемент в последнем добавленном массиве.

дождь
источник
1
Спасибо, решение с count()может быть полезно в некоторых случаях, но ваш пример не сработает для чего-то подобногоnew \ArrayObject([123 => "a", 456 => "c"]);
Trendfischer
@Trendfischer Я знаю, поэтому я использовал appendвместо конструктора, использование append с вашим примером, безусловно, будет работать. $array->append([123 => "a", 456 => "c"]
дождь
@Trendfischer Обратите внимание, countчто не для элементов вашего массива, а для многомерного массива, который appendбудет создан . Для вашего массива мы используем endкак обычно.
дождь
1
Я ценю это намерение, но обычно я не использую ArrayObject в качестве простой замены массива. Пример в вопросе является примерным, чтобы показать проблему. Хотя, если бы я только использовал append(), я мог бы использовать count(), это правильное решение. Это может работать с append('a')и append('b'). Ключом было бы запретить ассоциативные массивы, что возможно путем расширения ArrayObject.
Trendfischer