Una notevole miglioria di PHP7 è senza ombra di dubbio l'inserimento di un operatore di confronto combinato che viene chiamato Spaceship per semplicità comunicativa: infatti è un operatore di confronto che assomiglia tantissimo ad una navetta spaziale stilizzata, un pò come se fosse una emoticon.
Questo operatore è semplicemente definito come <=>
E' un operatore che va utilizzato per la comparazione di scalari, quindi, di numeri interi, bool, float, e stringhe, ma anche per la comparazione di Array e Oggetti. Ecco un esempio:
<?php
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
La particolarità di questo operatore è che al posto di definire un "vero o falso", come accade per i suoi fratelli <, >, <= e >=, la sua mappa di verità è leggermente diversa, e permette di avere 3 stati di ritorno:
- 0: se entrambe le espressioni sono UGUALI
- 1: se l'espressione di SINISTRA è maggiore
- -1: se l'espressione di DESTRA è maggiore
Ora, ragionando un secondo su espressioni scalari "stringa", questo operatore fa quello che ha sempre fatto la funzione strcmp di php.
<?php
// qui è chiaramente visibile il comportamento dell'operatore Spaceship, che è assolutamente identico alla funzione strcmp per le stringhe
$a = 'aeroporto';
$b = 'piscina';
echo strcmp ( $a, $b ); // -1
echo $a <=> $b; // -1
La vera potenza di questo operatore è che rende la scrittura di funzioni di ordinamento custom molto più veloce da scrivere: ecco un esempio di stessa identica funzione di ordinamento custom, usando il "vecchio" triplo if, e usando il nuovo operatore Spaceship:
<?php
$numeri = [ 0 => [ 'v' => 10 ], 1 => [ 'v' => 20 ], 2 => [ 'v' => 30 ], 3 => [ 'v' => 10 ], 4 => [ 'v' => 40 ], 5 => [ 'v' => 40 ] ];
// vecchio metodo di ordinamento
usort ( $numeri, function ( $n1, $n2 ) {
if ( $n1['v'] == $n2['v'] ) return 0;
else if ( $n1['v'] < $n2['v'] ) return 1;
else return -1;
});
// nuovo metodo di ordinamento
usort ( $numeri, function ( $n1, $n2 ) {
return $n1['v'] <=> $n2['v'];
});
Vediamo invece qualche esempio di confronto tra più di un tipo di variabile e i relativi ritorni di verità:
<?php
// Interi
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
// Float
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1
// Stringhe
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
echo "a" <=> "aa"; // -1
echo "zz" <=> "aa"; // 1
// Array
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1
// Oggetti
$a = (object) ["a" => "b"];
$b = (object) ["a" => "b"];
echo $a <=> $b; // 0
$a = (object) ["a" => "b"];
$b = (object) ["a" => "c"];
echo $a <=> $b; // -1
$a = (object) ["a" => "c"];
$b = (object) ["a" => "b"];
echo $a <=> $b; // 1
// solo i valori vengono confrontati, non le chiavi: in questo caso i valori sono "b" e "b" in entrambi gli oggetti
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; // 0
La migliore applicazione di questo comparatore è l'utilizzo in funzioni di ordinamento custom:
<?php
class Veicolo {
public $nome;
public $velocitaMassima;
public function __construct ( string $nome, int $velocitaMassima ) {
$this -> nome = $nome;
$this -> velocitaMassima = $velocitaMassima;
}
}
$veicoli = [
new Veicolo ( 'Panda', 160 );
new Veicolo ( 'Punto', 180 );
new Veicolo ( 'Giulia', 240 );
new Veicolo ( 'Ape', '50' );
new Veicolo ( 'Ducato', 160 );
new Veicolo ( 'Z4', 240 );
];
// ordinamento per nome
usort ( $veicoli, function ( $v1, $v2 ) {
return $v1 -> nome <=> $v2 -> nome;
});
echo $veicoli[0] -> name; // Ape
// ordinamento per velocità massima
usort ( $veicoli, function ( $v1, $v2 ) {
return $v1 -> velocitaMassima <=> $v2 -> velocitaMassima;
});
echo $veicoli[0] -> name; // Giulia
Vediamo come si comporta l'operatore Spaceship di PHP 7 quando utilizzato su ordinamenti di valori multipli. Questa tecnica semplifica enormemente l'ordinamento di array o oggetti basando l'ordinamento su più chiavi.
<?php
usort ( $veicoli, function ( $v1, $v2 ) {
return [ $v1 -> velocitaMassima, $v1 -> nome ] <=> [ $v2 -> velocitaMassima, $v2 -> nome ];
});
foreach ( $veicoli as $veicolo ) {
echo 'La velocità massima di "' $veicolo -> nome . '" è ' . $veicolo -> velocitaMassima . '\n';
}
// Stampa:
// La velocità massima di "Ape" è 50
// La velocità massima di "Ducato" è 160
// La velocità massima di "Panda" è 160
// La velocità massima di "Punto" è 180
// La velocità massima di "Giulia" è 240
// La velocità massima di "Z4" è 240
Sfruttando la comparazione di array, questa funzione di ordinamento ha richiesto 1 sola riga per essere scritta, al posto delle 6 o 7 richieste precedentemente.
Questa era la seconda lezione su PHP 7. Naviga nella categoria PHP7 di questo blog per scoprire le altre lezioni e le novità introdotte da PHP7.