ArrayObject não funciona com end () no PHP 7.4

9

Ao migrar para o PHP 7.4, eu tenho que lidar com um comportamento diferente de algumas funções de array como reset(), current()ou end()relativas a ArrayObject. O exemplo a seguir produz saídas diferentes:

<?php

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


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

Com o php 7.4, a saída é:

bool(false)
string(1) "b"

Nas versões do PHP anteriores à 7.4, a saída é a seguinte:

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

A end($array->getArrayCopy())produz um aviso, mas pode ser uma solução alternativa se usado com uma variável.

Existe uma maneira de imitar o comportamento de end()com um ArrayObjectou ArrayIterator? O ArrayObject pode ser muito grande, uma iteração até o final pode não ser a melhor solução.

Trendfischer
fonte
Uma alternativa poderia ser $item = $array[count($array)-1];. Não tenho certeza se essa é a solução mais eficiente.
Patrick Q
2
Eu diria que se qualifica como um bug do PHP, não há definitivamente nada no changelog que sugira que essa foi uma alteração pretendida na
versão
Teste-o on-line: 3v4l.org/4MADI
0stone0
11
@PatrickQ e se for associativo?
Andreas
4
@iainn isso definitivamente não é um bug - php.net/manual/pt/…
u_mulder

Respostas:

2

A partir do PHP 7.4, os métodos de array não operam em array interno, mas por ArrayObjectsi só. Resumi duas soluções para isso.

1. Obtendo matriz interna de objeto.

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

2. Criando Fachada ArrayObjecte adicionando o método personalizado end () à classe atualizada.

Tajniak
fonte
0

Você pode fazer do array um objeto para obter as chaves e usar end nas teclas para obter a última chave.

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

var_dump($array[$end_key]);

Não é uma solução bonita, mas funciona.
Eu sugiro que você faça uma função para poder chamá-la quando necessário.

https://3v4l.org/HTGYn

Como uma função:

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
fonte
Não vejo diferença entre as duas respostas quando olho o resultado e o usaqe em questão. se diferença explicar por favor
Dlk 21/02
11
Testei a array_keys()solução com 3v4l.org/IaEMM/perf#output, mas ela precisava de 20 a 30% a mais de memória em comparação com uma end()simples getArrayCopy() 3v4l.org/uYv59/perf#output
Trendfischer
11
@Trendfischer Se a memória é o problema e se você deseja endapenas usá -lo, é possível criar uma classe de wrapper que implemente ArrayAccesse tenha uma função adicional que retorne um endarray interno interno que seria operado.
vivek_23 21/02
11
@ vivek_23 parece uma boa resposta
Trendfischer 21/02
3
Pergunta: qual é o propósito array_keys? por que você não o lança diretamente $arr = (array) $arraye depois$end = end($arr)
Rain
0

Uma abordagem um pouco mais rápida sem converter ou usar um iterador seria não usar o construtor em primeiro lugar e, em vez disso, usar o appendmétodo que criará uma matriz em si e você poderá usá end-la posteriormente

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

count($array) - 1caso você acrescente outra matriz posteriormente, garantimos que esse $itemseja sempre o último elemento da última matriz anexada.

Chuva
fonte
11
Obrigado, a solução com count()pode ser útil em alguns casos, mas o seu exemplo não funcionaria para algo como istonew \ArrayObject([123 => "a", 456 => "c"]);
Trendfischer
@ Trendfischer Eu sei que é por isso que usei, em appendvez do construtor, usar o apêndice com seu exemplo definitivamente funcionará. $array->append([123 => "a", 456 => "c"]
Rain
@ Trendfischer Observe que countnão é para os elementos da sua matriz, é para a matriz multidimensional que appendserá criada. Para sua matriz, estamos usando endcomo de costume.
Rain
11
Aprecio a intenção, mas geralmente não uso um ArrayObject como um simples substituto para uma matriz. O exemplo da pergunta é exemplar para mostrar o problema. Embora se eu apenas usar append(), poderia usar uma count()solução válida. Isso poderia funcionar com append('a')e append('b'). A chave seria desabilitar matrizes associativas, o que é uma possibilidade, estendendo ArrayObject.
Trendfischer