"Blank"と"Null"と0にまつわる「undefined」の話

2015年3月15日

PHP プログラミング

今回はPHPについての話ですが、この概念はプログラム全般に言える内容なので、プログラム初心者は覚えておいて損はないと思います。 プログラムをしていて、予期せぬ結果になる事はしばしばあると思いますが、大体が凡ミスレベルであれば、修正も簡単なんですが、原因が全くつかめないという事も少なくないかもしれません。 そんな中で、僕がこの概念を理解できるまで、結果を出すのに苦労した事をメモします。

if文判定

以下の判定の結果について、違和感が湧くでしょうか? <?php $str = ""; if(is_null($str)){echo "It's null.";} else{echo "It's not null.";} # [結果] : It's null. 次に以下のプログラムではどうでしょう? <?php $str = ""; if(!$str){echo "It's null.";} else{echo "It's not null.";} # [結果] : It's null. 最後に、さらに別の判定です。 <?php $str = ""; if($str==""){echo "It's null.";} else{echo "It's not null.";} # [結果] : It's null. 全て同じ結果ですが、$strの型が変わると、結果が変わることがあります。

型を変えてみる

プログラムを増やすと面倒くさいので、まとまったファイルで記述します。 <?php $str = 0; echo "1:"; if(is_null($str)){ echo "It's null.\n"; } else{ echo "It's not null.\n"; } echo "2:"; if(!$str){ echo "It's null.\n"; } else{ echo "It's not null.\n"; } echo "3:"; if($str==""){ echo "It's null.\n"; } else{ echo "It's not null.\n"; }

結果

1:It's not null. 2:It's null. 3:It's null. 1番は、0という数値が入ったので、nullではなくなりましたが、 2番と3番は、少し不思議に感じませんか? ここが、もっともややこしかった内容で、if文は「true」と「false」の判定を行うという事を考えていたのですが、「empty」という事も意識しないといけないと知りました。 「null」と「empty」が違うというのは、分かりやすく言うと、nullはバイトアドレスの0番目にあたるが、emptyは、「空」という点が違っている。 少し分かりにくいですが、コードアドレスをもっているか持っていないかという明確な違いがあるので、判定が違うのも当然という事ですね。 それを考えると、「!$str」「$str==""」「is_null」は厳密に判定内容が違うという事ですね。 書き方が違うので当たり前なんですが、これを理解するのが少し苦しみました。

1つずつ考えてみる

is_null

$str=null; という風に、nullという値が代入しているという風に理解するとこの判定は、nullのみの判定であることがわかります。 ただし、以下のプログラムもnull判定されるので少し注意は必要ですね。 ※PHPにおける変数宣言はnullがデフォルトで代入されていると理解しておいてもいいでしょう。 <?php $str; if(is_null($str)){ echo "It's null.\n"; } else{ echo "It's not null.\n"; }

!$str

やっかいなのはこの「!」という判定。 基本的にはif文の真偽を反転させるという事なのだが、「0」という数値の値が「false(偽)」になるという事が、理解し難いのですが、おそらく2進数の「0」「1」で真偽判定をしていた事の名残かと考えると、まあまあ理解できるようにはなりましたが、進数が変わっているところで、この判定を使うのは少し危険なのかもしれませんね。

$str==""

この判定は、言語において色々と判定が別れるトコロなんですが、PHPにおいては、「==」という判定は、「型宣言を無視して、不等判定をする」という意味合いになりますが、「!」と同じように、「0」も「false」扱いになる点を注意しなければいけません。 ちなみに最近の言語では主流になってきている「===」という書き方は「型宣言を含めて判定」という事で、厳密に判定するのであれば、こちらを使うことをオススメします。

余談ですが「==」と「===」の速度の違い

プログラムの速度を向上させる事は、プログラマの使命なのですが、いったいこの2つはどちらを使うほうが効果的なのかというと、 「===」の方が若干速度は向上します。 他のプログラムでも同じ理由で、速度向上が見込めるのですが、その理由とは、 「==」を使用すると、型宣言を無視するので、違う型どおしの場合、言語の裏側で型変換を行っていると思われます。「===」を使うことで、型変換の処理が走らない分、速度が向上するという事なんですね。

どの書き方がいいのか?

それでは、変数にデータが入っているかどうかの判定を行う場合はどの書き方が一番いいかというと、 扱う型、null判定かempty判定か、どの判定を行うかで、判定方法は変わってくるので、一概にどれがいいという決め方はできないというのが現状です。 とりあえず、javascriptなども含めて、型の概念が低い言語に関しては、こういう箇所を突き詰めてどのタイプの時にどの判定が望ましいかを見つけてみてください。 基本的には、本記事に書かれている内容を理解できたら、答えはそんなに難しくはないと思います。