Как оператор космического корабля PHP <=> обрабатывает несопоставимые операнды?
В PHP 7 будет добавлен оператор космического корабля. Я не уверен, как он работает в некоторых крайних случаях.
$a <=> $b
вернусь:
- 1 если $a> $ b
- 0 если $a == $ b
- -1 если $a <$ b
Что произойдет, если значения не сопоставимы?
Какие типы переменных можно сравнить?
1 ответ
Просто! Запрос на тягу, в котором реализован оператор, относится к функции с именем compare_function
во внутренностях PHP, так что вам просто нужно прочитать compare_function
200-строчная реализация макро-тяжелого C, и вы сможете понять поведение для себя. Структуры управления имеют глубину всего 4 уровня, и вызывается всего несколько десятков макросов и других функций; это должно быть легко!
...
Хорошо, я признаю это, я не достаточно умен, чтобы снять все это. Так что давайте просто сделаем несколько экспериментов.
Если <
, ==
а также >
может обрабатывать операнды последовательно, то так может <=>
Большинство типов в PHP можно сравнивать с другими типами благодаря жонглированию типов. В любом случае, оператор космического корабля будет вести себя так, чтобы <
, ==
а также >
,
Например, давайте попробуем использовать строку и int:
php > var_dump(3 < 'bla');
bool(false)
php > var_dump(3 == 'bla');
bool(false)
php > var_dump(3 > 'bla');
bool(true)
php > var_dump(3 <=> 'bla');
int(1)
Или с null
и ресурс:
php > $fp = fopen('test', 'r');
php > var_dump(null > $fp);
bool(false)
php > var_dump(null == $fp);
bool(false)
php > var_dump(null < $fp);
bool(true)
php > var_dump(null <=> $fp);
int(-1)
Или с плавающей точкой и массивом:
php > var_dump(1.0 > []);
bool(false)
php > var_dump(1.0 == []);
bool(false)
php > var_dump(1.0 < []);
bool(true)
php > var_dump(1.0 <=> []);
int(-1)
Во всех этих случаях результат $a <=> $b
именно так и должно быть в документах: -1
если $a < $b
, 0
если $a == $b
, а также 1
если $a > $b
,
Но если ни один из <
, ==
а также >
вернуть истину, космический корабль запутывается и возвращает 1
Хотя приведение типов позволяет сравнивать большинство значений различных типов друг с другом, так что ровно одно из $a < $b
, $a == $b
а также $a > $b
Это правда, есть несколько крайних случаев, в которых это не имеет места. В этих случаях результат $a <=> $b
1, что не очень значимо или полезно.
Например, давайте сравним несколько объектов разных классов:
php > class Foo {}
php > class Bar {}
php > $a = new Foo;
php > $b = new Bar;
php > var_dump($a < $b);
bool(false)
php > var_dump($a == $b);
bool(false)
php > var_dump($a > $b);
bool(false)
php > var_dump($a <=> $b);
int(1)
php > var_dump($b <=> $a);
int(1)
или некоторые неравные массивы, где ни один строго не больше другого:
php > $a = ['foo' => 'bar'];
php > $b = ['bar' => 'foo'];
php > var_dump($a < $b);
bool(false)
php > var_dump($a == $b);
bool(false)
php > var_dump($a > $b);
bool(false)
php > var_dump($a <=> $b);
int(1)
php > var_dump($b <=> $a);
int(1)
<=>
также может бросать предупреждения
Если мы сравниваем объект с int, мы получаем предупреждение, как если бы мы делали это с любым другим оператором сравнения:
php > $a = new stdclass;
php > var_dump($a <=> 1);
PHP Notice: Object of class stdClass could not be converted to int in php shell code on line 1
int(0)
Результаты для несопоставимых типов, очевидно, бесполезны и могут запутать все, что ожидает от оператора космического корабля последовательного упорядочения значений различных типов. Так что не используйте его в обстоятельствах, когда он может делать бессмысленные сравнения, подобные этим.