mattintosh note

どこかのエンジニアモドキの備忘録

PHPのnull判定について調べてみる

わけあって書きたくなかった PHP 関連の作業をすることになりました。なんてこった。

いままで PHP を書いて生きてこなかったんですが、まぁ Go とか Python とか他の言語の知識である程度はなんとかなるものです。

とは言っても PHP 学習歴数時間の人間の話です。

とりあえず既存プログラムの改修をしているのですが、う〜ん、どうもこれ PHP というかプログラミングを知らない人間が書いている気がする…と思ったので言語独自の解釈の確認から。(まぁ私もプログラマではないのですが)

で、まぁよくある null の確認です。

f:id:mattintosh4:20191228013415p:plain
https://www.php.net/manual/ja/types.comparisons.php

あぁ、これ見るだけで嫌になりますね。ポイントになるのは上の 4 項目でしょうか。

  • 空文字
  • null
  • 未代入
  • 未定義

似ているようで異なるこれらのパターンですが、この表を見る限り is_null()isset() は真逆の解釈をするようです。つまり is_null() == !isset() または !is_null() == isset() という話です。

PHP だしそんなことないよな〜」と思っていたら案の定違いがありました。

<?php
var_dump($foo);
var_dump(is_null($foo));
var_dump(!isset($foo));
PHP Notice:  Undefined variable: foo in /tmp/sh-thd-6879852719 (deleted) on line 2
NULL
PHP Notice:  Undefined variable: foo in /tmp/sh-thd-6879852719 (deleted) on line 3
bool(true)
bool(true)

判定は is_null()isset() も同じく true ですが、isset() は変数が Undefined であっても E_NOTICE を吐かないようです。

公式の説明では下記のように書いてあります。(誤字なんとかしろよ)

注意:

$xが定義されていない状態で単に if ($x)としてしまうとE_NOTICE レベルのエラーが発行てしまいます。代わりに、empty()や isset()を使うかあるいは変数を初期化するように してください。

この説明に is_null() が含まれていないところを見ると is_null()E_NOTICE を吐くのでしょう。

E_ERROR ではないのだからいいのではないかと済ます人もいるでしょうが私はそういうのが嫌いです。きちんと対処すれば出力されないメッセージのおかげで大事なメッセージが埋もれてしまいます。インフラ的観点からしてもログファイルが肥大化するので勘弁して欲しいです。

で、上の表からするに PHP では「変数が定義済みかどうかわからない状態で厳密に $foo = nullを正確に調べる方法は is_null()isset() 単体では調べられないのでは?」と思った。

PHP の公式には null について下記のように書いてある。null の範囲が広すぎない?

  • 定数 NULL が代入されている場合。
  • まだ値が何も代入されていない場合。
  • unset() されている場合。

上の説明を読むに空文字は「値」に含まれないようだ。シェルで言うところの test -n "${foo}" レベルの判定しかしないっぽい。

SQL では厳密に null を判定する方法として is null があったりするけど、DB と組み合わせて使う PHP の null の解釈がこれではユーザが混乱するのではないだろうか。

コーディングルールも nulltruefalse は小文字で書けと言いつつ、定数だから大文字書くべきなのでは?と思ったり。

厳密に null かどうかを判別するのは同ページの === による厳密な比較 に書いてあるがこれだけなようだ。

$foo === null

is_null()isset() などは複数のパターンで判定するのに使えるが厳密なチェックには使えない、と。

やっぱりヤダ PHP