PHPは自由度が高く、サクッと動くものを作るのに適した自分のような初心者にも優しい、素晴らしい言語ですよね。
一方で、自由度の高さゆえに意図しない挙動を示すことが多々あり、ある程度サービスの規模が大きくなってくると、思わぬ罠に引っかかったりすると思います。
そこで、PHPを書き始めてから3ヶ月ほど経ち、だんだん知見も溜まってきたので
個人的にPHPを書くときに気をつけたいと思ったことをリストアップしてみたいと思います。
(随時更新予定)
in_arrayはデフォルトで型の比較をしない
第一引数に指定した値が、第二引数のarrayに含まれているかどうかを判断するin_array
という関数、けっこう多くの場面で使うのではないでしょうか?
$value = $this->getValue();
$targets = array(
'hoge',
'fuga',
'piyo',
);
if (in_array($value, $targets)) {
// やりたい処理
}
こんな感じで$targets
に処理を行いたい対象を列挙しておいて、$value
が対象だったら処理をする、みたいな使い方をすると思います。
しかしこのin_arrayで行われる比較、デフォルトでは型の比較を行わない、==
での比較になっているので注意が必要です。
例えば
in_array(0, [0, 1, 2]);
// -> true
// 意図した挙動
in_array(3, [0, 1, 2]);
// -> false
// これも意図した挙動
in_array('hoge', [0, 1, 2]);
// -> true !?
// 意図しない挙動(PHP8.0からはfalseを返すようになりました)
このような形で、第二引数のarrayに'hoge'
という文字列を含んでいないのにもかかわらずtrueになってしまいます。(PHP8.0からは変更になりました。)
これは==
によって、文字列の'hoge'
が暗黙的にint型に変換されてから比較されるためです。
PHPでは'hoge'
のような数字以外の文字列をint型に変換すると基本的に0
になります。(JSなどではNaNになる)
intval('hoge');
// -> 0
では、厳密に比較したい場合、つまり===
にしたい場合はどうすればいいのかというと、in_array
関数の第三引数にtrueをつければOKです。すると===
で比較を行ってくれるようになります。
in_array('hoge', [0, 1, 2], true);
// -> false
// ===で比較している
チームでin_arrayを使うときは必ず第三引数を指定する、というルールにしてもいいかもしれません。
参考 https://qiita.com/ritukiii/items/3a6add378ae089ab5d70
2021/07/20追記
PHP7.4までは上記の挙動のとおりですが、PHP8.0からは変更になったようです。
(コメントいただきありがとうございます。)
PHP8.0からは、==
の挙動が変わりました。文字列と数字を比較する際、これまでは文字列を数値に変換していましたが、PHP8.0からは数値を文字列に変換するようになりました。
つまり"hoge" == 0
を実行するとき、数値の0
が文字列の"0"
に変換され、その上で"hoge"
と"0"
が比較されます。これらの文字列は異なっているため、PHP7.4までとは違い、これはfalseを返します。
これに伴い、==
で比較を行うin_array
も挙動が変わったということです。
メソッドやクラスで大文字と小文字の区別をしない
プログラミング言語の一般的な話として、関数名や変数名などで大文字、小文字の区別をすることをcase-sensitive、逆に区別せず同一視することをcase-insensitiveといいます。
PHPでは関数名、メソッド名、クラス名などがcase-insensitiveになっているので注意が必要です。
例えば
function hoge() {
echo 'some message';
}
hoge();
// -> some message
Hoge();
// -> some message
hOgE();
// -> some message
こんな感じでも関数が呼び出せてしまいます。ここまでわざとらしい書き方をすることはないと思いますが、URI
とかID
などの表記揺れが起こりそうな関数名の場合、普通に動いてしまってタイポに気づかないことがありそうです。
function getUri(){
//
}
getURI();
// -> エラーなく動いてしまう
// Uriとかで検索したときにヒットしない
特にリファクタリングなどの際、この関数使ってるかな?ということで小文字で検索し、引っかからなかったから消したら実は大文字で使っていた箇所があって障害に繋がる、なんてことがありそうなので注意しましょう。
参考 https://qiita.com/tadsan/items/6c6329eeb43929271119
&&とand, ||とor
一般的に使われている&&
や||
の他にand
, or
という演算子も存在しているそうです。
そしてこれらは演算子としての優先順位が異なるため、注意が必要です。
ハマりそうな優先順位としては、上から順に
- &&, ||
- = (代入演算子)
- and, or
となっているのでand
やor
をつかうと下記のように、意図しない挙動を示すことがあります。
$a = false || true;
// -> $aはtrue
// 意図した挙動
$b = true && false;
// -> $bはfalse
// 意図した挙動
$c = false or true;
// -> $cはfalseになる
// 意図しない挙動
// orの評価よりも先に$c = falseの代入が行われるため
$d = true and false;
// -> $dはtrueになる
// 意図しない挙動
// andの評価よりも先に$d = trueの代入が行われるため
基本的にはand
, or
を使わず&&
, ||
を使えばいいと思いますが、「どうせ同じだろ〜」といきおいで使うと痛い目をみそうです。
参考 https://www.php.net/manual/ja/language.operators.logical.php
最後に
いかがだったでしょうか?
今後も数を増やしていきPHPを書くときのチェックリストのようにしていきたいと思っています。
バージョンxxからは改善されてるよ!みたいなことがあればコメントなどで教えていただけると嬉しいです。