Help us understand the problem. What is going on with this article?

【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 と未定義の区別が必要なデータ構造は設計を誤っている。

mpyw
古い記事はそのまま参考にしないようにご注意ください
synapse
Synapseは、オンラインサロンサービスにおけるパイオニアとして、かつて存在していたスタートアップです。
https://synapseam.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away