Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

PHP7: spaceship operator

В ПХП7 вошёл новый оператор — «космический корабль». Я его помню со времён программирования на Перле. Наиболее частое применение он, по всей видимости, найдёт в сортировках:

usort($data, function ($o1, $o2) {
    return $o1->value <=> $o2->value;
});

Комбинация «меньше», «равно» и «больше» — и есть «космический корабль». Результат его выполнения следующий — если левое меньше, получается «-1», если правое — «1», если значение равны, вернётся ноль. Для строк уже сейчас (с чётвертой версии языка) существует функция strcmp, которая делает то же.

Новый оператор сравнивает даже массивы и объекты, в RFC есть соответствующие примеры:

echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1

$a = (object) ["a" => "b"];
$b = (object) ["a" => "c"];
echo $a <=> $b; // -1
 
$a = (object) ["a" => "c"];
$b = (object) ["a" => "b"];
echo $a <=> $b; // 1
 
// only values are compared
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b; // 0

В общем, какой-то особенной пользы в язык конструкция не принесёт, но в в неких частных случаях читаемость улучшится.

8 комментариев
Кай 2015

Всё-таки, комбинация меньше», «равно» и «больше».

hshhhhh.name 2015

ну можно будет иногда if() менять на switch() что меня всегда радует :)

Евгений Степанищев (bolknote.ru) 2015

Комментарий для Кай:

И правда. Не понимаю почему я так написал.

Евгений Степанищев (bolknote.ru) 2015

Комментарий для hshhhhh.name:

можно будет иногда if() менять на switch()

В каких случаях?

Svan 2015

Наверно так:
-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
switch( a <=> b)
{
   case -1: break;
   case 1: break;
   case 0: break;
};
-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​

Svan 2015

Но где это применить практически — непростой вопрос.

Svan 2015

Хотя...
Например, промежутки дат:
дата начала больше даты финиша — ошибка
дата начала совпадает с датой финиша — нормально, обработать одним образом
дата начала меньше даты финиша — нормально, обработать другим образом.

Денис Радченко 2018

Не знал, что можно сравнивать массивы. Теперь вместо

return ($a[’order’] <=> $b[’order’]) ?: ($a[’name’] <=> $b[’name’])

буду писать

return [$a[’order’], $a[’name’]] <=> [$b[’order’], $b[’name’]];