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 может быть очень большим, итерация до конца может оказаться не лучшим решением.


Альтернатива может быть $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 () в обновленный класс.


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

Я не вижу разницы между обоими ответами, когда я смотрю на результат и используемое вопрос. если разница объясните пожалуйста
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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.