Ordinare e confrontare dati con l’operatore spaceship in PHP

by theArchitect
SHARE
Ordinare e confrontare dati con l’operatore spaceship in PHP
© Guida-HTML5.it

Introduzione

Tra gli operatori meno conosciuti di PHP, ma molto utili nella pratica, troviamo l’operatore spaceship, rappresentato da <=>. Il suo nome richiama la forma di una navicella spaziale e deriva dal fatto che confronta due valori restituendo una direzione precisa del confronto.

L’operatore <=> confronta il valore a sinistra con quello a destra e restituisce:

  • -1 se il primo valore è minore del secondo;
  • 0 se i due valori sono equivalenti;
  • 1 se il primo valore è maggiore del secondo.

Questo comportamento è particolarmente utile quando si devono ordinare array con usort(), perché la funzione di confronto richiesta da PHP deve restituire proprio un numero negativo, zero o positivo. Invece di scrivere diversi blocchi if, possiamo quindi usare direttamente l’operatore spaceship.

È importante non confonderlo con un normale operatore di uguaglianza o con un confronto booleano. L’espressione $a <=> $b non restituisce true o false, ma un valore numerico che indica il risultato del confronto.

Codice completo

<?php

$prodotti = [
    [
        ´nome´ => ´Tastiera meccanica´,
        ´prezzo´ => 89.90,
    ],
    [
        ´nome´ => ´Mouse wireless´,
        ´prezzo´ => 29.90,
    ],
    [
        ´nome´ => ´Monitor 27 pollici´,
        ´prezzo´ => 249.00,
    ],
    [
        ´nome´ => ´Webcam Full HD´,
        ´prezzo´ => 59.90,
    ],
];

// Ordina i prodotti dal prezzo più basso al prezzo più alto.
usort($prodotti, function (array $prodottoA, array $prodottoB): int {
    return $prodottoA[´prezzo´] <=> $prodottoB[´prezzo´];
});

echo "<h2>Prodotti ordinati per prezzo crescente</h2>";
echo "<ul>";

foreach ($prodotti as $prodotto) {
    echo "<li>";
    echo htmlspecialchars($prodotto[´nome´], ENT_QUOTES, ´UTF-8´);
    echo " - ";
    echo number_format($prodotto[´prezzo´], 2, ´,´, ´.´) . " euro";
    echo "</li>";
}

echo "</ul>";

// Lo stesso ordinamento in senso decrescente.
// Basta invertire i due operandi.
usort($prodotti, function (array $prodottoA, array $prodottoB): int {
    return $prodottoB[´prezzo´] <=> $prodottoA[´prezzo´];
});

echo "<h2>Prodotti ordinati per prezzo decrescente</h2>";
echo "<ul>";

foreach ($prodotti as $prodotto) {
    echo "<li>";
    echo htmlspecialchars($prodotto[´nome´], ENT_QUOTES, ´UTF-8´);
    echo " - ";
    echo number_format($prodotto[´prezzo´], 2, ´,´, ´.´) . " euro";
    echo "</li>";
}

echo "</ul>";

// Esempi semplici di confronto.
var_dump(3 <=> 8);   // int(-1)
var_dump(5 <=> 5);   // int(0)
var_dump(10 <=> 2);  // int(1)

Spiegazione

Il risultato dell’operatore

Consideriamo tre espressioni:

<?php

echo 4 <=> 9;   // -1
echo 7 <=> 7;   // 0
echo 12 <=> 3;  // 1

Nel primo caso, 4 è minore di 9, quindi il risultato è negativo. Nel secondo caso i valori sono uguali e viene restituito 0. Nell’ultimo caso, 12 è maggiore di 3, quindi il risultato è positivo.

Il valore restituito non deve essere necessariamente esattamente -1 o 1 in ogni tipo di confronto interno: ciò che conta è il segno del risultato. Tuttavia, con numeri e confronti comuni PHP restituisce normalmente questi valori.

Ordinamento crescente e decrescente

La funzione usort() riceve un array e una funzione di confronto. La funzione viene chiamata più volte per confrontare coppie di elementi. Se restituisce un valore negativo, il primo elemento viene considerato precedente al secondo; se restituisce zero, i due elementi sono equivalenti per l’ordinamento; se restituisce un valore positivo, il primo elemento viene dopo il secondo.

Per ordinare in modo crescente si scrive:

return $a[´valore´] <=> $b[´valore´];

Per invertire l’ordine è sufficiente scambiare gli operandi:

return $b[´valore´] <=> $a[´valore´];

Ordinare per più criteri

Un caso realistico consiste nell’ordinare prima per prezzo e, quando due prezzi coincidono, per nome. Possiamo combinare lo spaceship con un secondo confronto:

<?php

usort($prodotti, function (array $a, array $b): int {
    $confrontoPrezzo = $a[´prezzo´] <=> $b[´prezzo´];

    if ($confrontoPrezzo !== 0) {
        return $confrontoPrezzo;
    }

    return $a[´nome´] <=> $b[´nome´];
});

In questo modo il nome viene usato soltanto quando i prezzi sono uguali.

Best practice

  • Usa tipi omogenei: confronta numeri con numeri e stringhe con stringhe. Evita array in cui lo stesso campo contiene talvolta un numero e talvolta una stringa non numerica.
  • Indica i tipi delle funzioni: dichiarare array per i parametri e int per il risultato rende il codice più leggibile e facilita l’individuazione degli errori.
  • Gestisci i valori mancanti: prima di confrontare un campo come prezzo, assicurati che esista e abbia un valore valido.
  • Non usare lo spaceship per verificare solo l’uguaglianza: se vuoi sapere se due valori sono uguali, un confronto esplicito è più chiaro.
  • Usa funzioni dedicate per casi complessi: per ordinamenti con regole articolate, estrai la logica in una funzione nominata invece di creare callback troppo lunghe.
  • Ricorda che usort() reindicizza l’array: se le chiavi originali sono importanti, valuta funzioni di ordinamento che le preservano, come uasort().

Riepilogo

L’operatore spaceship <=> confronta due valori e restituisce un numero negativo, zero o positivo. È una soluzione compatta e leggibile per costruire funzioni di ordinamento con usort(), soprattutto quando si lavora con array di record, prodotti, utenti o risultati di query.

La forma principale è:

$a <=> $b

Per un ordinamento crescente si confrontano normalmente i valori; per un ordinamento decrescente si scambiano gli operandi. Quando servono più criteri, si può eseguire un secondo confronto solo se il primo restituisce zero.

Approfondisci con risorse ufficiali

  • Manuale PHP: pagina ufficiale sugli operatori di confronto, inclusa la documentazione dell’operatore spaceship.
  • Manuale PHP: documentazione della funzione usort() per ordinare array tramite una funzione di confronto personalizzata.
  • Manuale PHP: documentazione della funzione uasort() per ordinare mantenendo le chiavi associate agli elementi.
  • PHP Language Reference: sezione ufficiale dedicata agli operatori e alle regole di confronto tra valori.

SHARE