+39 3662317539/+34 620899163
info@simonecosci.com

PHP 8.5: array_first, array_last e l’operatore pipe

Sviluppo Siti Web a Tenerife

PHP 8.5: array_first, array_last e l’operatore pipe

PHP 8.5 è uscito il 20 novembre 2025 ed è in supporto attivo fino al 31 dicembre 2027 (php.net/supported-versions). Tra le novità ce ne sono due che si incontrano ogni giorno scrivendo codice: due funzioni nuove sugli array e un operatore nuovo. Nessuna delle due è rivoluzionaria. Tutte e due tolgono di mezzo del rumore che c’era da vent’anni.

array_first() e array_last(): la fine di un trucco

Prendere il primo valore di un array in PHP non ha mai avuto una funzione dedicata. Si usava reset():

$primo = reset($lista);

Funziona, ma fa una cosa che non avete chiesto. La firma documentata è reset(array|object &$array): mixed: l’array arriva per riferimento, perché reset() riavvolge il puntatore interno dell’array e poi restituisce il primo elemento (manuale, reset). Leggere un valore modifica la struttura da cui lo state leggendo. È esattamente il motivo per cui l’RFC che ha introdotto le funzioni nuove parla di trucchi «semanticamente sbagliati»: “Existing ‘tricks’ like reset() and end() are semantically the wrong approach because they modify the ‘internal iterator’ of the array” (RFC array_first/array_last).

C’è un secondo problema, più insidioso. reset() restituisce false sull’array vuoto — e false è anche un valore legittimo che un array può contenere. Il manuale lo dice apertamente: “This function may return Boolean false, but may also return a non-Boolean value which evaluates to false”. Su un array di flag, reset($a) === false non distingue «l’array è vuoto» da «il primo elemento è false».

Da 8.5 ci sono due funzioni che fanno solo quello che dicono:

array_first(array $array): mixed
array_last(array $array): mixed

Nessun &, quindi nessun effetto sul puntatore interno. Restituiscono null sull’array vuoto, per coerenza con array_shift() e array_pop() che già si comportavano così. E non si fanno ingannare dalle chiavi: l’esempio del manuale è deliberatamente un array con le chiavi in disordine.

$array = [1 => 'a', 0 => 'b', 3 => 'c', 2 => 'd'];

var_dump(array_first($array)); // string(1) "a"
var_dump(array_last($array));  // string(1) "d"

Notate array_first() che torna 'a', non 'b'. Primo significa primo in ordine di inserimento, non chiave più bassa. È lo stesso motivo per cui $array[0] è sbagliato tutte le volte che l’array non è una lista: dopo un array_filter() le chiavi hanno buchi e $array[0] può non esistere affatto.

Le altre scorciatoie che circolano hanno ciascuna il suo difetto. $array[array_key_first($array)] è corretto ma prolisso — l’RFC lo chiama “cumbersome” — e va comunque protetto sull’array vuoto, perché array_key_first() lì torna null e state indicizzando con null. array_values($array)[0] ricopia l’intero array per leggerne un elemento: su dieci elementi non si vede, su centomila sì. E reset() prende l’argomento per riferimento, quindi non potete passargli direttamente il ritorno di un metodo: reset($ordine->getRighe()) non è codice valido, array_first($ordine->getRighe()) sì.

Documentazione: array_first, array_last, entrambe marcate (PHP 8 >= 8.5.0).

L’operatore pipe |>

Il secondo pezzo è sintattico. |> prende il valore a sinistra e lo passa come unico argomento al callable a destra, valutando al risultato della chiamata (manuale, operatori funzionali). Queste due righe sono equivalenti:

$result = "Hello World" |> strlen(...);
$result = strlen("Hello World");

Su una chiamata sola non serve a niente. Serve quando le chiamate sono incatenate, perché PHP le scrive al contrario: la funzione applicata per ultima è quella che si legge per prima, e la variabile di partenza finisce in fondo, sepolta sotto le parentesi. Con il pipe si legge nell’ordine in cui le cose accadono:

$slug = $titolo
    |> trim(...)
    |> (fn($str) => str_replace(' ', '-', $str))
    |> strtolower(...);

L’alternativa classica è una catena di $temp = ... che serve solo a tenere insieme i passaggi. Il pipe la elimina senza inventare nulla: è zucchero sintattico per quelle assegnazioni, niente di più.

La sintassi strlen(...) non è nuova di 8.5: sono le first-class callable arrivate in PHP 8.1, dove i tre puntini fanno parte della sintassi e producono una Closure (manuale). A destra del pipe va bene qualunque callable valido: una closure, una first-class callable, un oggetto con __invoke().

Dove ci si fa male

Tre regole, tutte documentate, tutte scoperte al primo tentativo se non le si conosce.

Un solo parametro obbligatorio. Il callable a destra riceve un argomento e basta. Una funzione con più parametri obbligatori “will fail as if the function were called normally with insufficient arguments”. È per questo che nell’esempio sopra str_replace() sta dentro una arrow function: prende tre argomenti, e il pipe ne passa uno.

Niente parametri per riferimento. L’RFC è esplicito: “pass-by-ref callables are disallowed on the right-hand side of a pipe operator”. Quindi tutta la famiglia sort(), usort(), array_push() — le funzioni che modificano l’array invece di restituirne uno nuovo — resta fuori. Il pipe è per il codice che trasforma valori e li restituisce, non per quello che muta in loco.

Le arrow function vanno tra parentesi. Obbligatorie, altrimenti è un errore fatale: senza parentesi il parser non sa dove finisce il corpo della fn. L’errata dell’RFC lo mette per iscritto — “parentheses are now required around an arrow function when used in a pipe chain” — e non vale per le first-class callable, che infatti nell’esempio stanno nude.

Sulla precedenza, l’RFC dice che il pipe “binds before comparison operations so that its result may be compared, but after mathematical operations”, ed è associativo a sinistra: il lato sinistro viene valutato per primo. In pratica una catena di pipe si valuta dall’alto verso il basso, come si legge.

Serve aggiornare?

array_first() e array_last() sì, appena il vostro hosting arriva a 8.5: sostituiscono codice che oggi funziona ma dice il falso su cosa sta facendo, e lo fanno senza cambiare nient’altro. Il pipe è un gusto: rende leggibili le catene di trasformazioni e non aggiunge niente dove le catene non ci sono.

Il consiglio pratico riguarda la versione, non le funzioni. PHP 8.1 è fine vita e 8.2 riceve solo fix di sicurezza fino al 31 dicembre 2026: se il vostro sito gira su una di queste due, il problema da mettere in agenda non sono le funzioni nuove, è il ramo su cui state. 8.3 e 8.4 sono in supporto attivo, 8.5 lo è fino a fine 2027.

Se non sapete su che versione gira il vostro sito e volete saperlo prima che ve lo dica un errore, scriveteci.