読者です 読者をやめる 読者になる 読者になる

NissyBlog

Life goes on.

UFOの型比較

この記事はAdvent Calendar 2015 - VOYAGE GROUP techlogの4日目の記事になります。
こんにちは。@nissy0409240です。
VOYAGE GROUPでエンジニアをしています。

気温もぐっと低くなり、いよいよ冬本番となって参りました。
夜空を見上げれば奇麗なオリオン座や流れ星、もしかしたらUFOだって見えるかもしれません。
そこで、今日はUFOについて書いていこうと思います。

UFOについて

まずはUFOの正式名称から考えていきましょう。
kotobank.jp
UFOという言葉は「Unidentified Flying Object」の略称であり、
正式には「未確認飛行物体」というそうです。

更に調査を進めていくと、色々な形状のUFOが存在するかもしれないことが分かりました。
そこで、皆さんにUFOをイメージして頂くために、
弊社で動くhubot、jewelpetにUFOの画像を出して貰いました。
f:id:Nissy0409:20151204092743p:plain
アスキーアートでも書けそうな形状ですね。
少し小さくて恐縮ですが、ターミナルで書くとこんな感じで書けました。
f:id:Nissy0409:20151203012436p:plain
演算子みたいなかたちをしていますね。

UFO演算子とは

と言う訳で、ここからはUFO演算子について書いていこうと思います。
UFO演算子について端的に述べるとすれば、
「両辺の値の大小比較の為に用いる演算子
と述べることが出来ます。

箇条書きで書くと下記のようになります。

  • 「左辺 < 右辺」の時は-1を返す
  • 「左辺 = 右辺」の時は0を返す
  • 「左辺 > 右辺」の時は1を返す

具体的な挙動はこちらになります。

$ ruby -e 'puts 1<=>2'
-1
$ ruby -e 'puts 1<=>1'
0
$ ruby -e 'puts 2<=>1'
1

ちなみに、このUFO演算子は先日リリースされたPHP7で追加されました。
さっそく、下記のufo.phpファイルを作成し、

<?php
    echo 1 <=> 2, PHP_EOL;
    echo 1 <=> 1, PHP_EOL;
    echo 2 <=> 1, PHP_EOL;

挙動を確認してみます。

$ php ufo.php
-1
0
1

RubyPHPの挙動の違い

このUFO演算子Rubyでは0、-1、1だけを返す訳ではありません。
下記の様に、

$ ruby -e 'p 1<=>"ほげほげ"'
nil

というように、型が違う為に比較不能な場合はnilを返します。

では、PHPではどうでしょうか。
先ほどのufo.phpに一行を足して実行してみます。

<?php
    echo 1 <=> 2, PHP_EOL;
    echo 1 <=> 1, PHP_EOL;
    echo 2 <=> 1, PHP_EOL;
    echo 1 <=> "ほげほげ", PHP_EOL;
$ php ufo.php
-1
0
1
1

(;つД⊂)ゴシゴシ
念のため、もう一行足してみます。

<?php
    echo 1 <=> 2, PHP_EOL;
    echo 1 <=> 1, PHP_EOL;
    echo 2 <=> 1, PHP_EOL;
    echo 1 <=> "ほげほげ", PHP_EOL;
    echo "ほげほげ" <=> 1, PHP_EOL;
$ php ufo.php
-1
0
1
1
-1

Σ(・ω・ノ)ノ!
nullが返ってくると思いきや、比較処理が走っていました。
では、型の違う同じ値だったらどうでしょう。

<?php
    $ufo = (int)1;
    $ufo_2 = (string)1;
    echo $ufo <=> 2, PHP_EOL;
    echo $ufo <=> 1, PHP_EOL;
    echo $ufo <=> 0, PHP_EOL;
    echo $ufo <=> "ほげほげ", PHP_EOL;
    echo "ほげほげ" <=> $ufo, PHP_EOL;
    echo $ufo <=> $ufo_2, PHP_EOL;
$ php ufo.php
-1
0
1
1
-1
0

同じ値として評価されていました。

PHP RFCを読んでみる

どうしてこの挙動をするのか確かめるべく、
PHP: rfc:combined-comparison-operatorを読んでみると、
Proposalにはこのような一文があり、

Add a new operator (expr) <=> (expr), it returns 0 if both operands are equal, 1 if the left is greater, and -1 if the right is greater. It uses exactly the same comparison rules as used by our existing comparison operators: <, <=, ==, >= and >.

下記の様な表も掲載されていました。
f:id:Nissy0409:20151204022324p:plain
つまり、二項の型が異なる型の場合はキャストされた状態で比較するということ。
具体例を見てみても、0、-1、1が返ってきていたことから、
厳密比較では評価しないということが分かりました。

おまけ

PHP: rfc:combined-comparison-operatorによると、

This "three-way comparison operator", also known as the “spaceship operator”

であるとのこと。
UFO演算子の正式名称は「三方比較演算子」といい、
「UFO演算子」という名前は略称とのことです。

という訳で本エントリーは「UFOの型比較」改め、「UFO演算子の型比較」をお送り致しました。
最後までお付き合い頂き、ありがとうございました。
明日は@yuu_itoさんです。
お楽しみに!!

※参考
PHP 7 リリース内容の確認 - Qiita
Ruby - 三方分岐とUFO演算子 - Qiita
PHP: rfc:combined-comparison-operator