1. はじめに
4月からPHPを書いています。if文による真偽判断で、数値と数値表記の文字列を比較するコードを書いた際、少し苦しんでしまい、しかしキレイな解決策を思いつかなかったお話です。
2. どんなコードを書こうとしたのか
Webシステムの入力フォームで、プルダウンリスト <select>
とその選択肢 <option>
を生成する箇所です。遷移元の画面の入力値をPOSTで受取り、POSTで受取った値に該当する選択肢には selected="selected"
を付加し、初期値として表示します。
POST値が null
のときは、selected="selected"
である選択肢がないため、一番上の「未選択」が初期表示になる、という寸法です。
<select name="pulldownlist">
<option>未選択</option>
<?php
/*
* $list_items は選択肢の配列。
* $key はゼロからの連番。
* $post_value は文字列型の数字か null。
*/
foreach($list_items as $key => $value) {
if($post_value == $key) { // == で比較していた
echo "<option value=${key} selected=\"selected\">${value}</option>";
} else {
echo "<option value=${key}>${value}</option>";
}
}
?>
</option>
このような例で、POST値は null
なのに $key
が 0
の選択肢が初期表示されるという状態になり、他の箇所のコードがおかしいのかなあと探し回ったのですが、結局原因は if 内の ==
による比較でした。
3. 悩みどころと解決策
PHPでは ==
が暗黙の型変換をするんですね。かといってこういうケースの場合、 ===
でもうまくいきません。
<?php
/*
* null と 0 の比較は false に、"1" と 1 の比較は true になってほしい。
*/
// == を使うと…どちらも真になる!
null == 0; // => true
"1" == 1; // => true
// === を使うと…どちらも偽になる!
null === 0; // => false
"1" === 1; // => false
どうするのが正解なのかしばらく考えた挙げ句、コードは汚く見えますが、止むを得ず次のように書くことにしました。
<?php
// キャストしたうえで === による厳密比較
null === (string)0; // => false
"1" === (string)1; // => true
こうすれば、POST値が空の場合と値が入っている場合のいずれにも対応ができます。
4. おわりに
キャストを使うなんて…なんだかもうちょっとスクリプト言語らしく(?)書きたいところだったよな~と思いつつも、結局キャストに落ち着いてしまいました。初期値の表示もするプルダウンリストをつくるなんて、ザラにあると思うんですが、今後もこう書いていく、のか…?
もっといいスマートな解決法がありましたら、ご指南いただけますとうれしいです。
単純な比較演算で悩むとは思わなかったので、今回記事に書いてみた次第です。