Edited at

【PHP入門講座】 NULLと未定義の違い

More than 5 years have passed since last update.


目次に戻る


NULLと未定義


NULL型

NULL という型があります。PHPでは null と書きます。大文字小文字は区別されません。以下のコードを実行してみましょう。


PHPコード

<?php

$var = null;
var_dump($var);


実行結果

NULL


TRUE FALSE NULL をまとめて 三値 と呼ぶことがありますが、これらを漢字一文字で表すと



  • TRUE … 真


  • FALSE … 偽

  • NULL … 無

として解釈されます。命題「今日は学校に行く日か?」で例えると、



  • TRUE …今日は学校に行く日である


  • FALSE … 今日は休みの日である

  • NULL … そもそも中退してた

のようなイメージです。


未定義(Undefined)

NULL と言いながらも…



PHPコード

<?php

$var = null;
var_dump($var);


確かにこの例では変数 $var は値 NULL を持つものとして存在していました。ここで別の例を考えてみましょう。


PHPコード

<?php

var_dump($var);


実行結果

PHP Notice:  Undefined variable: var in ...

NULL

「変数varが未定義だよ!」 という Notice を発生しながらも、何故か NULL と表示されていますね。PHPでは、未定義の値を取得しようとしたときに、Noticeを発生しながら NULL を代わりに取得します

また、配列において未定義のキーから値を取得しようとしたときにも、エラーメッセージは微妙に違いますが同様のNoticeが発生します。


PHPコード

<?php

$var = array('A', 'B');
var_dump($var[2], $var['foo']);


実行結果

PHP Notice:  Undefined offset: 2 in ...

NULL
PHP Notice: Undefined index: foo in ...
NULL

PHPプログラマは、


  • Noticeを気にせずに手抜きコーディングをする人

  • Noticeの発生に気を付けて丁寧にコーディングする人

に大分されると思いますが、もちろんここでは後者を目指してコーディングを行っていきます。Noticeが発生するだけで処理速度が大幅に低下するので、これを潰すメリットはかなり大きいです。


Noticeを出さずに未定義をチェックする方法

ここからは少し復習も入ります。

【PHP入門講座】 想定外の入力への対応

http://qiita.com/mpyw/items/f298828002bbc488fe89

こちらで既に少し触れていますが、 isset 構文を用いる方法があります。 isset は関数ではなく言語構文であるが故に、未定義の変数から値を取得しようとしてもNoticeを発生しないという強力な特長を持っています。


isset が真を返す条件


通常の変数


  • 変数が 定義 されている

  • 且つ、 NULL 以外 の値を取る


PHPコード

<?php

$v2 = null;
$v3 = false;
var_dump(isset($v1), isset($v2), isset($v3));


実行結果

bool(false)

bool(false)
bool(true)


配列のキー


  • キーが 定義 されている

  • 且つ、 NULL 以外 の値を取る


PHPコード

<?php

$v = array();
$v[1] = null;
$v[2] = false;
var_dump(isset($v[0]), isset($v[1]), isset($v[2]));


実行結果

bool(false)

bool(false)
bool(true)


NULL と未定義を区別する方法

まず真っ先に思いつくのは、値を取得しようとしてみてエラーが発生したかどうかをチェックする、という方法でしょう。しかし、これにはいろいろ制約が多く、現実的な方法ではありません。そこで別の方法を考えてみましょう。


配列におけるキーが存在するかどうか

array_key_exists 関数を利用します。これは、キーが定義されているときに必ず TRUE を返します。 NULL でも TRUE となります。これが isset 構文との大きな違いです。

array_key_exists

http://php.net/manual/ja/function.array-key-exists.php


PHPコード

<?php

$v = array();
$v[1] = null;
$v[2] = false;
var_dump(
array_key_exists(0, $v),
array_key_exists(1, $v),
array_key_exists(2, $v)
);


実行結果

bool(false)

bool(true)
bool(true)


グローバル空間における変数が存在するかどうか

グローバル空間 とは、関数内ではない、要するに 一番外側の空間 を指します。今まで扱ってきた場所はほとんどグローバル空間です。グローバル空間にある変数は グローバル変数 といいます。

PHPでは、グローバル空間にある変数を スーパーグローバル変数 $GLOBALS で配列として取得することが出来ます。スーパーグローバル変数に関しては後で詳しく学習するので、ここでは軽く流してください。


PHPコード

<?php

$v2 = null;
$v3 = false;
var_dump(
array_key_exists('v1', $GLOBALS),
array_key_exists('v2', $GLOBALS),
array_key_exists('v3', $GLOBALS)
);


実行結果

bool(false)

bool(true)
bool(true)


関数内における変数が存在するかどうか

グローバル空間では変数 $GLOBALS が用意されていましたが、関数内では get_defined_vars 関数の返り値を利用します。

get_defined_vars

http://php.net/manual/ja/function.get-defined-vars.php


PHPコード

<?php

function test() {
$v2 = null;
$v3 = false;
var_dump(
array_key_exists('v1', get_defined_vars()),
array_key_exists('v2', get_defined_vars()),
array_key_exists('v3', get_defined_vars())
);
}
test();


実行結果

bool(false)

bool(true)
bool(true)


NULL と未定義を区別しようと思うな!!!

いろいろやってきましたが、正直 面倒くさい ですよね。普通に配列をチェックするだけなら素直に array_key_exists を使えばいいような気もしますが、動作速度は isset の方が速いです。

【結論】 NULL と未定義の区別が必要なデータ構造は設計を誤っている。