Supongamos que tengo la siguiente función recursiva para convertir una matriz en un generador:
function traverse(array $items): Generator { if (!empty($items)) { yield $items[0]; array_shift($items); yield from traverse($items); } } Ejecutar esta función e iterar sobre el Generador a través de un foreach da el resultado esperado:
$values = traverse(['a', 'b', 'c', 'd', 'e']); foreach ($values as $value) { echo $value; } // 'abcde' is echoed Sin embargo, cuando uso la función incorporada iterator_to_array() , obtengo el siguiente resultado:
$values = iterator_to_array(traverse(['a', 'b', 'c', 'd', 'e'])); foreach ($values as $value) { echo $value; } // Only 'e' is echoedEsperaría que ambas piezas de código se comportaran de manera idéntica, pero no es así. ¿Por qué su comportamiento es diferente?
Estoy ejecutando esto en PHP 8.1.
Del manual :
yield from no restablece las claves . Conserva las claves devueltas por el objeto o matriz Traversable. Por lo tanto, algunos valores pueden compartir una clave común con otro rendimiento o rendimiento de, que, al insertarse en una matriz, sobrescribirá los valores anteriores con esa clave.
Un caso común en el que esto es importante es iterator_to_array() que devuelve una matriz con clave de forma predeterminada, lo que puede generar resultados inesperados. iterator_to_array() tiene un segundo parámetro use_keys que se puede establecer en falso para recopilar todos los valores mientras se ignoran las claves devueltas por el Generador.
Su generador devuelve un elemento con la misma clave cada vez (porque se restablecen después de la llamada array_shift ), por lo que iterator_to_array sobrescribe cada elemento con el siguiente. Es por eso que solo está viendo que se devuelve el elemento final.
Si pasa el argumento use_keys a la función como false , obtendrá el comportamiento deseado, por ejemplo
$values = iterator_to_array(traverse(['a', 'b', 'c', 'd', 'e']), false);