どーも。ばぁどです。
Qiitaには久々の投稿だと思います。
Rubyが一番のお気に入り。
現在はDrupalを勉強中。
セキュリティに興味ありのプログラマ歴5年目の鳥です。
PHPはプログラマ1年目の時に1ヶ月弱触りました。
ここ3ヶ月はGitから眺めている程度で、久々にサンプルを書いて動かしています。
普段は、はてなブログの方を更新しているのですが、
今回はとある研修中にどうしても理解できないPHPコードがあったので、調べて共有。
これ、どうなの?
簡略化しますが、下記のようなコードを目にしました。
※コード自体は業務のコードではなく、一般公開されているもの
<?php
$target = 'valid target';
if($target == !isValid($target)) {
// エラー処理(エラー文言入れて画面に表示)
echo 'false';
return 'something';
}
// ビジネスロジックが続く
isValid()
メソッドは下記のようなものを想像してくれればいいと思う
/**
* 何かしらの値(メールアドレスや電話番号)が正当か確認するメソッド
*/
function isValid($target) {
// $targetの正当性を検証してtrue or false を返す
}
文字列の検証を行うメソッドが自分のことを、is×××
と名乗っているのだから、true
or false
を返してくれるだろう。という、淡い期待。(実際はそんな感じでした)
問題なのが、if文の中身。
文字列とtrue
かfalse
を比べてる???
これってどうなるの???
この書き方どうなの?という疑問。
調べ直したこと
falseと判定される定義
PHPの false
になる定義をずいぶん昔に聞いたことがある。
詳しくは覚えていないが、とりあえず酷いということだけは覚えていた。
上記のマニュアルからすると、下記の7つの属性がfalse
として判断される。
- boolean の false
- integer の 0
- float の 0
- 空の文字列、および文字列の0
- 要素の数が0の配列
- 特別な値NULL
- 空のタグから作成された SimpleXML オブジェクト
なるほど。。。
ゼロはどうしてもfalse
として扱いたいらしい。
PHPはゼロに恨みでもあるのか。
Rubyが false
と nil(NULL)
だけをfalse
として判定するのがとても素晴らしい仕様なんだと感じる。
緩やかな比較と厳密な比較
PHP の比較には緩やかな比較と、厳密な比較がある。
PHP 型の比較表
==
は緩やかな比較。
型を見ずに、上記のfalse と判定される定義以外同士のものであれば全てtrue
。
===
は厳密な比較。
型と値があっているかを確認する。
今回は、==
が使われているので緩やかな比較が行われている。
ロジックの検証
上記の調査結果から、今回は文字列とboolean
を対象に緩やかな比較をしていることがわかった。
ここで厄介なのが、isValid()
の前に ! (NOT) を入れていること。
isValid()
で返ってくる値を反転させて、文字列と比較している。
おそらく、コードを書いた人はfalse
が返ってきた時に条件式の処理を入れたかったのだろう。
なるほど、こういうロジックになるのもなんとなく分かる。
このソースコードを言語化すると下記のようになる。
文字列と検証結果を逆転したものを条件式で判定して、falseであれば正常ロジックの処理を続行するよ。
文字列と検証結果を逆転したものを条件式で判定して、trueであればエラー処理をしてreturnで返却するよ。
もう、最初の一文目を読むだけで混乱する。
はぁ、こんな書き方ができるからPHPはダ(ry
あれ?これって書き方の問題なのでは?
こんな書き方ができるから、PHPはダメなんだ!!!!と言いたくなる気持ちをグッと堪えた。
違うよね。
書き方がおかしいんだよ。
そもそもisValid()
で返ってきたものと文字列を比較する意味ってあるん?
要するにisValid()
がtrue
なのか、false
なのかだけでいいんじゃないの?
これじゃダメ?(変更点はifの条件式のみ)
<?php
$target = 'valid target';
if(!isValid($target)) {
// エラー処理(エラー文言入れて画面に表示)
echo 'false';
return 'something';
}
// ビジネスロジックが続く
少なくとも、僕ならレビューで弾く。
きっと上記のような書き方になった理由があるだろうから、もう少し調査はします。
さらに問題発見
これ、文字列の0
みたいに、false
として判定される値を入れたら、メールアドレスや電話番号の形式じゃなくてもtrue
として処理されるんじゃね??
<?php
$target = '0'; //★ここが0★
if($target == !isValid($target)) {
echo 'false'; // エラー処理(エラー文言入れて画面に表示)
return 'something';
}
// ビジネスロジックが続く
上記実行したら、条件式の中に入らずに通りました。
ダメじゃん。
まとめ
最近、他人が書いたPHPをGitから眺めているのだが、やっぱりなれん。
$変数だとか、アロー演算子だとか。
まだまだPHPとお友達になれていないということか。
自分が実際にPHPを書くときにクソコードを大量生産しないように気をつけよう。
PHPerとしてはまだまだ未熟。
もっとPHPになれないとなー。
日々是精進、心を磨く! オネスト・ハート!
きっと優秀なPHPerになったら新垣結衣さんと結婚できると信じて!!
※余談ですが、私は土屋太鳳ちゃんが好きです