LoginSignup
3
2

More than 5 years have passed since last update.

PHPの条件式が読めなかったお話

Posted at

どーも。ばぁどです。
Qiitaには久々の投稿だと思います。

Rubyが一番のお気に入り。
現在はDrupalを勉強中。
セキュリティに興味ありのプログラマ歴5年目の鳥です。

PHPはプログラマ1年目の時に1ヶ月弱触りました。
ここ3ヶ月はGitから眺めている程度で、久々にサンプルを書いて動かしています。

普段は、はてなブログの方を更新しているのですが、
今回はとある研修中にどうしても理解できないPHPコードがあったので、調べて共有。

これ、どうなの?

簡略化しますが、下記のようなコードを目にしました。
※コード自体は業務のコードではなく、一般公開されているもの

sample01.php
<?php

$target = 'valid target';

if($target == !isValid($target)) {
  // エラー処理(エラー文言入れて画面に表示)
  echo 'false'; 
  return 'something';
}

// ビジネスロジックが続く

isValid()メソッドは下記のようなものを想像してくれればいいと思う

isValid.php
/**
* 何かしらの値(メールアドレスや電話番号)が正当か確認するメソッド 
*/
function isValid($target) {
  // $targetの正当性を検証してtrue or false を返す
}

文字列の検証を行うメソッドが自分のことを、is×××と名乗っているのだから、true or falseを返してくれるだろう。という、淡い期待。(実際はそんな感じでした)

問題なのが、if文の中身。

文字列とtruefalseを比べてる???
これってどうなるの???
この書き方どうなの?という疑問。

調べ直したこと

falseと判定される定義

PHPの falseになる定義をずいぶん昔に聞いたことがある。
詳しくは覚えていないが、とりあえず酷いということだけは覚えていた。

論理型 (boolean)

上記のマニュアルからすると、下記の7つの属性がfalseとして判断される。

  • boolean の false
  • integer の 0
  • float の 0
  • 空の文字列、および文字列の0
  • 要素の数が0の配列
  • 特別な値NULL
  • 空のタグから作成された SimpleXML オブジェクト

なるほど。。。
ゼロはどうしてもfalseとして扱いたいらしい。
PHPはゼロに恨みでもあるのか。

Rubyが falsenil(NULL) だけをfalseとして判定するのがとても素晴らしい仕様なんだと感じる。

緩やかな比較と厳密な比較

PHP の比較には緩やかな比較と、厳密な比較がある。
PHP 型の比較表

==は緩やかな比較。
型を見ずに、上記のfalse と判定される定義以外同士のものであれば全てtrue

===は厳密な比較。
型と値があっているかを確認する。

今回は、== が使われているので緩やかな比較が行われている。

ロジックの検証

上記の調査結果から、今回は文字列とbooleanを対象に緩やかな比較をしていることがわかった。

ここで厄介なのが、isValid()の前に ! (NOT) を入れていること。

isValid()で返ってくる値を反転させて、文字列と比較している。

おそらく、コードを書いた人はfalseが返ってきた時に条件式の処理を入れたかったのだろう。
なるほど、こういうロジックになるのもなんとなく分かる。

このソースコードを言語化すると下記のようになる。

文字列と検証結果を逆転したものを条件式で判定して、falseであれば正常ロジックの処理を続行するよ。
文字列と検証結果を逆転したものを条件式で判定して、trueであればエラー処理をしてreturnで返却するよ。

もう、最初の一文目を読むだけで混乱する。

はぁ、こんな書き方ができるからPHPはダ(ry

あれ?これって書き方の問題なのでは?

こんな書き方ができるから、PHPはダメなんだ!!!!と言いたくなる気持ちをグッと堪えた。
違うよね。
書き方がおかしいんだよ。

そもそもisValid()で返ってきたものと文字列を比較する意味ってあるん?
要するにisValid()trueなのか、falseなのかだけでいいんじゃないの?
これじゃダメ?(変更点はifの条件式のみ)

sample02.php
<?php

$target = 'valid target';

if(!isValid($target)) {
  // エラー処理(エラー文言入れて画面に表示)
  echo 'false';
  return 'something';
}

// ビジネスロジックが続く

少なくとも、僕ならレビューで弾く。
きっと上記のような書き方になった理由があるだろうから、もう少し調査はします。

さらに問題発見

これ、文字列の0みたいに、falseとして判定される値を入れたら、メールアドレスや電話番号の形式じゃなくてもtrue として処理されるんじゃね??

sample03.php
<?php
$target = '0'; //★ここが0★

if($target == !isValid($target)) {
  echo 'false'; // エラー処理(エラー文言入れて画面に表示)
  return 'something';
}

// ビジネスロジックが続く

上記実行したら、条件式の中に入らずに通りました。
ダメじゃん。

まとめ

最近、他人が書いたPHPをGitから眺めているのだが、やっぱりなれん。
$変数だとか、アロー演算子だとか。
まだまだPHPとお友達になれていないということか。
自分が実際にPHPを書くときにクソコードを大量生産しないように気をつけよう。

PHPerとしてはまだまだ未熟。
もっとPHPになれないとなー。
日々是精進、心を磨く! オネスト・ハート!

きっと優秀なPHPerになったら新垣結衣さんと結婚できると信じて!!
※余談ですが、私は土屋太鳳ちゃんが好きです

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2