RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

【PHP】比較演算子を振り返ろう!

はじめに

おはようございますこんにちはこんばんは。
筆者はPHPの経験がまだ2年に満たない程度なのですが、PHPの比較は何かとクセがあるなぁと思いながらコーディングする日々です。宇宙船演算子エルビス演算子など筆者もまだあまり使いこなせていない面白い演算子もありますので、学習も含めて改めて皆さんと一緒に比較演算子を見ていこうというのが本記事の趣旨となっております。

大前提

==や!=を書くのは控えましょう

既存からあるものならともかく新規で生み出すのは止めましょう。思いも寄らない比較結果になる可能性があります。新規で書く場合は===!==を使いましょう。逆に既存からあるものを===に置き換えるのは注意しましょう。一見大丈夫そうに見えても思わぬ値が入ってきて既存と判定が変わってしまう場合があります。

型を揃えて比較しましょう

1つ目の大前提で等しい・等しくないについては問題無くなりましたが、><についてはまだ問題が残ります。例えばですが、2 > "1" は想定通りtrueになります。実際PHPはこの場合stringの"1"を数字としてみなし、比較を行います。基本的に数字型文字列を使っている場合は問題ないのですが、そもそも別の型同士を比較すること自体あまりしっくりこないですし、今後言語仕様に変更がある恐れも大いにあるのであくまで同じ型同士で比較することを心がけましょう。

基本の比較演算子

演算子 説明
== 等しければtrue 曖昧な比較
=== 等しければtrue 厳密な比較
!= 等しくなければtrue 曖昧な比較
<> !=と同じ 曖昧な比較
!== 等しくなければtrue 厳密な比較
< 左辺が右辺より小さければtrue
<= 左辺が右辺より小さいか等しければtrue
> 左辺が右辺より大きければtrue
>= 左辺が右辺より大きいか等しければtrue

曖昧な比較と厳密な比較

簡単にいうと曖昧な比較は==で厳密な比較は===です。JavaScriptと同じ感覚ですね。曖昧な比較は、PHPが型の相互変換を行なってくれて比較結果を返してくれます。逆に厳密な比較は型についてもチェックを行います。型が違えばその時点で別物と見なすのです。当然と言えば当然な気もしてきますが、以下のような結果の差が出てきます。

<?php
1 == "1"             // true
1 === "1"            // false

これはまだ簡単な方でnull0が絡み出すと一気に複雑になります。他言語を同時に書いている人はそのままの流れで==を使わないように気をつけましょう。Javaを使っている人にはstringの比較を==で行わずにequals()で行うのと同じような感覚で厳密な比較を使っていただけるとわかりやすいかなと思います。また、曖昧な比較で使用される型の相互変換にはルールが存在するので過去コードを読み解くときには公式ドキュメントとにらめっこしましょう。

宇宙船演算子

<=> これが宇宙船演算子です。全てのプログラミング言語にあるわけではないので初めて聞いた方もいらっしゃるのではないでしょうか。そういう私もPHPを初めてから知りました。この演算子は以下のように判定されます。

パターン 結果
左辺が右辺より小さい -1
左辺が右辺より大きい 0
左辺と右辺が等しい 1

一応この演算子は文字列や配列に対しても使用できるのですがあまり直感的ではないですし、数値に対して使いましょう。便利そうに見えていつ使うんだろう?というような演算子ですね。実際、通常のコードに出てくることはあまりないと思います。なぜならこの比較結果によって3分岐するようなコードは設計から見直したほうが良い可能性が高いからです。sortを書く場合はとてもシンプルに書けるようになるのでまたその時に思い出してみてください。sortはひたすら大きい小さい等しいの比較を連続して行うので便利です。
ちなみになぜ宇宙船演算子かというと<=>の形がスターウォーズに出てくる宇宙船に形が似ているなど諸説あるそうです。(タイ・ファイターで検索してみてください)

三項演算子

みんな大好き?三項演算子です。以下のように書きます。
(1) ? (2) : (3)
判定は以下の通りです。

パターン 結果
(1)がtrue (2)
(1)がfalse (3)

少しわかりづらいのでコードっぽく書いてみましょう。

<?php
$おやつ = 洋菓子は好きですか() ? ケーキ : お饅頭

正確にはコードではないのですがこうするとわかりやすいです。「洋菓子は好きですか」関数がtrueならケーキがおやつ変数に入りますし、falseならお饅頭がおやつ変数に入ります。三項演算子を使わずに書くと以下の通りです。

<?php
if (洋菓子は好きですか()) {
    $おやつ = ケーキ
} else {
    $おやつ = お饅頭
}

こんなにも行数も書く量も変わってきます。もちろん最初のうちは三項演算子は読みづらいのですが慣れてくるととてもシンプルに見えてきます。変数代入だけでなくもちろん関数実行もできます。

<?php
$averageScore > 80 ? お小遣いプレゼント() : 参考書プレゼント()

ここで注意点ですが、何でもかんでも三項演算子を使えばいいというわけではありません。あくまで見やすくするため、すなわち可読性を上げるために使用してください。慣れないうちは一旦普通にif-else文で書いてから三項演算子に変換してみてください。そこで悩んでしまったり、出来た式を見た時に理解に時間がかかりそうなコードになってしまった時は三項演算子を使う場面では無いということです。例えば以下のような時は基本的に三項演算子を無理に使用する必要はありません。

  • if文がネストしている
  • else ifが入ってきて3分岐以上になる
  • if文の中の行数が2行以上ある

特にPHPは他の言語と違い三項演算子を左から右に読んでいくので、1行に複数の三項演算子が積み重なっている場合は他言語使用者からすると全く違う結果になってしまいます。PHP8.0以上では()を使用して1つの三項演算子の範囲を明確にしてあげないとエラーになります。それでも読みにくいことは確かなので極力控えましょう。

エルビス演算子

?:
PHPの公式ドキュメントにはエルビス演算子というワードは出てこないのですが、いわゆるエルビス演算子というやつです。こちらは三項演算子の短縮記法の1つです。見ての通り三項演算子の条件式がtrueだった時の部分(三項演算子の紹介項目でいう(2)の部分)がギュッと圧縮された形になります。書き方は以下のような形。

<?php
$貰えるお小遣い = $テストの点数 ?: 1

微妙にわかりにくくなってしまったような気がしますが、テストの点数が1点以上(true)ならそのぶんのお小遣いをあげ、テストの点数が0(false)なら0は可哀想なので1だけお小遣いをあげます。要するにtrueだった場合は条件式の値がそのまま値になります。falseだった場合は三項演算子の場合と同じで:の右側が値として入ります。これをエルビス演算子を使わずに三項演算子で書くと以下のようになります。

<?php
$貰えるお小遣い = $テストの点数 ? $テストの点数 : 1

$テストの点数を2回書くことになってしまいました。これは確かに短縮したくなりますね。これも最初のうちはステップを踏むと書きやすいです。

  1. if-else文で書く
  2. 簡単に三項演算子で書けそう! → 三項演算子で書く
  3. 三項演算子の条件式とtrueの時に同じこと書いてる! → エルビス演算子で書く

以上のステップがスムーズに書けた時は完璧です。気持ちいいですね〜。慣れてくると一発で三項演算子で書けたり、エルビス演算子で書けたり、はたまたこれは普通にif-elseで書いた方が良いという判断が付くようになるのでif文を書くときは頭にこのステップを入れておきましょう。あくまで条件式の部分に入る値がfalsy(falseと同等の値)の時に右辺が値となることがポイントです。PHPの場合はこの後出てくるnull合体演算子と少し紛らわしいので注意してください。
ちなみにエルビス演算子の由来はエルビスプレスリーの顔文字から来ているらしいです。(Wikipedia)

null合体演算子

こちらもエルビス演算子とは別の三項演算子の短縮記法です。書き方は以下のような形。

<?php
$野菜 = $冷蔵庫['野菜室'] ?? 八百屋さんに買い物()

感覚としてはエルビス演算子と同じです。ただ、演算子の名前にもあるように??の左辺がnullだったときに右辺が値となります。null合体演算子を使わずに三項演算子で書くと以下の通り。

<?php
$野菜 = isset($冷蔵庫['野菜室']) ? $冷蔵庫['野菜室'] : 八百屋さんに買い物()

エルビス演算子の条件式部分に自動でisset()を付けてくれているような感じです。比較演算子なのにtrue,falseの判定じゃなくなったと思うかもしれませんが、実際には見えないisset()の返り値であるtrue,falseで判定しているのです。これだけ聞くとPHPではnullはfalsyなのでエルビス演算子だけでいいと思われるかもしれませんが、これまた便利な場面があるのです。それは配列のキー操作をする場合です。PHPのコードでやたらめったらisset()を使用してから配列操作を行なっているのを目にしたことはないでしょうか。一回エルビス演算子を使用して以下のコードを実行してみましょう。

<?php
$refrigerator = [];
$vegetable = $refrigerator['vegetableRoom'] ?: 'tomato';

実行結果は以下の通りです。

Warning: Undefined array key "vegetableRoom" in /tmp/preview on line 3

野菜室というキーは冷蔵庫配列に存在しないよ と怒られてしまうわけですね。   では、null合体演算子を使用して同じコードを実行してみましょう。

<?php
$refrigerator = [];
$vegetable = $refrigerator['vegetableRoom'] ?? 'tomato';

結果はエラーが出ないはずです。このまま$vegetableを出力すると中身は'tomato'です。ということでnullチェックをするときはnull合体演算子を使用した方が安全にチェックできるというわけです。使い道としてWebアプリケーションを想定するとして、フロント側からパラメータが配列で渡ってくることが多いと思います。その時、値を取り出して処理を行うわけです。ただ、全ての値がきちんと送られてくるとは限りません。空欄可のアンケートフォームもあるでしょう。そんな時、何も値がない場合は内部的にはデフォルト値として一定の値を使おうという場面が出てくるわけです。こういった場面ではnull合体演算子はとても短く処理を書く事ができます。例のコードだと、野菜室キーは野菜を入れるときに初めてキーを作成する可能性もあるわけで、それを全て考慮してコードを書くのは面倒くさいですよね。PHPではピタッと使いどきがハマる場面が結構あると思いますので存在を頭の中に入れておきましょう!

おわりに

本記事ではPHPの比較演算子を改めて見ていきました。言語の公式ドキュメントを読むのって楽しいですよね。本来調べたかったことと別の発見があったりしてついつい読んでしまいます。PHPにこんな機能があったんだとかこんな仕様なのかよ!と突っ込みたくなってしまったりと改めて基本の機能や仕様を見返してみると案外ベテランの方でも面白い発見があるかもしれません。PHPは何かとクセのある言語ですがそれも含めて愛おしい言語だと思いますので今後もPHPerライフ楽しんでいきましょう。

参考文献

PHP: 比較演算子 - Manual


エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。
20210916153018
https://career-recruit.rakus.co.jp/career_engineer/

カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.com

ラクスDevelopers登録フォーム
20220701175429
https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/

イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!

◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.