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.