14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHP, MySQL における NULL と 0

Posted at

コードレビューをしていたところ、「こんなの初めてっ!」ってくらい大量の is_null() を見た。ところによっては empty() や isset() が使われているので、意識して使い分けてるのか?と思ったけど、どうやら気分だったようなので、以下のような点を説明して直してもらった。

PHP における NULL 判定

isset(), empty(), is_null() の比較

変数の値($var) isset($var) empty($var) is_null($var)
""(空文字) ture ture
" "(スペース) ture ture
FALSE ture ture
TRUE ture
array() (空配列) ture ture ture
NULL true
"0" (文字列の 0) true true
0 (整数の 0) true true
0.0 (実数の 0) true true
var $var (宣言されたがセットされていない変数) true true
NULL byte ("\0") true

単純に NULL かどうかを判定したい場合、
$var !== null > !isset($var) > !empty($var) > !$var > !is_null($var)
の順で遅くなっていく。is_null() は関数なので呼び出しのオーバーヘッドがあって遅い。
isset() がよく使われてるような気がするが、NULL 判定だけなら、!== を使うのが良い。

== と === の比較

==/=== TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "php" ""
TRUE true/true true/false true/false true/false true/false true/false
FALSE true/true true/false true/false true/false true/false true/false
1 true/false true/true true/false
0 true/false true/true true/false true/false true/false true/false
-1 true/false true/true true/false
"1" true/false true/false true/true
"0" true/false true/false true/true
"-1" true/false true/false true/true
NULL true/false true/false true/true true/false true/false
array() true/false true/false true/true
"php" true/false true/false true/true
"" true/false true/false true/false true/true
あってるかな?

詳細は見にくいけど PHP 型の比較表

適当なプログラムで確認。

sample.php
<?php
 
$evaluateArray = array (NULL, 0, "0", "php");
$evaluateArrayDisplay = array ('NULL', '0',"\"0\"", "\"php\"");
 
foreach ($evaluateArray as $k => $var1) {
    foreach ($evaluateArray as $l => $var2) {
        if ($l > $k) {
            if ($var1 == $var2) echo "$evaluateArrayDisplay[$k] == $evaluateArrayDisplay[$l]\n";
            if ($var1 != $var2) echo "$evaluateArrayDisplay[$k] != $evaluateArrayDisplay[$l]\n";
            if ($var1 === $var2) echo "$evaluateArrayDisplay[$k] === $evaluateArrayDisplay[$l]\n";
            if ($var1 !== $var2) echo "$evaluateArrayDisplay[$k] !== $evaluateArrayDisplay[$l]\n";
        }
    }
}
 
exit;

結果

$ php --version
PHP 7.1.13 (cli) (built: Jan 25 2018 22:40:51) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.13, Copyright (c) 1999-2017, by Zend Technologies
 
 
$ php sample.php
NULL == 0
NULL !== 0
NULL != "0"
NULL !== "0"
NULL != "php"
NULL !== "php"
0 == "0"
0 !== "0"
0 == "php"
0 !== "php"
"0" != "php"
"0" !== "php"

ん〜、0 キモい。

MySQL の場合

例えば、こんな Address テーブルがあったとして

id(int) pref_cd(int) city_cd(int) name(varchar) roman(varchar)
745 14 0 神奈川県 NULL
746 14 100 横浜市 yokohama
747 14 101 鶴見区 yokohama_tsurumi

色々 select してみる。

mysql> select version();
+------------+
| version()  |
+------------+
| 5.6.35-log |
+------------+
1 row in set (0.02 sec)

mysql> select * from address where city_cd = 0;
+-----+---------+---------+--------------+-------+
| id  | pref_cd | city_cd | name         | roman |
+-----+---------+---------+--------------+-------+
| 745 |      14 |       0 | 神奈川県     | NULL  |
+-----+---------+---------+--------------+-------+
1 row in set (0.00 sec)

mysql> select * from address where city_cd = '0';
+-----+---------+---------+--------------+-------+
| id  | pref_cd | city_cd | name         | roman |
+-----+---------+---------+--------------+-------+
| 745 |      14 |       0 | 神奈川県     | NULL  |
+-----+---------+---------+--------------+-------+
1 row in set (0.00 sec)

mysql> select * from address where city_cd = '';
+-----+---------+---------+--------------+-------+
| id  | pref_cd | city_cd | name         | roman |
+-----+---------+---------+--------------+-------+
| 745 |      14 |       0 | 神奈川県     | NULL  |
+-----+---------+---------+--------------+-------+
1 row in set (0.00 sec)

mysql> select * from address where city_cd = null;
Empty set (0.00 sec)

mysql> select * from address where city_cd is null;
Empty set (0.00 sec)

mysql> select * from address where isnull(city_cd);
Empty set (0.00 sec)

mysql> select * from address where roman = 0;
+-----+---------+---------+-----------+------------------+
| id  | pref_cd | city_cd | name      | roman            |
+-----+---------+---------+-----------+------------------+
| 746 |      14 |     100 | 横浜市    | yokohama         |
| 747 |      14 |     101 | 鶴見区    | yokohama_tsurumi |
+-----+---------+---------+-----------+------------------+
2 rows in set, 2 warnings (0.00 sec)

mysql> select * from address where roman = '0';
Empty set (0.00 sec)

mysql> select * from address where roman = '';
Empty set (0.00 sec)

mysql> select * from address where roman = null;
Empty set (0.00 sec)

mysql> select * from address where roman is null;
+-----+---------+---------+--------------+-------+
| id  | pref_cd | city_cd | name         | roman |
+-----+---------+---------+--------------+-------+
| 745 |      14 |       0 | 神奈川県     | NULL  |
+-----+---------+---------+--------------+-------+
1 row in set (0.00 sec)

mysql> select * from address where isnull(roman);
+-----+---------+---------+--------------+-------+
| id  | pref_cd | city_cd | name         | roman |
+-----+---------+---------+--------------+-------+
| 745 |      14 |       0 | 神奈川県     | NULL  |
+-----+---------+---------+--------------+-------+
1 row in set (0.00 sec)

PHP と MySQL で NULL や 0 の扱いが少し違う。
PHP に素で書いてある SQL とかあんまりレビューしたくないけど、クエリを作る際に、"= 0" とか "= null" とかが混じってバグってるとか普通にありそうで、見直したくない。

14
9
2

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
14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?