PHPとJSの空チェック一覧

PHPの`empty`の挙動が不安になったのでまとめてみた。
ついでにJSの空チェックの挙動も調べた。
※ `empty()`を使う時は大抵`!empty()`(存在する)の形で使ってるので、この記事の中では全て`!empty()`の形で動作チェックをしています。

## PHPの場合
#### 空チェックリスト
公式マニュアルが見難いので、全て「存在する」側にまとめてみた。
PHP: PHP 型の比較表 - Manual
http://php.net/manual/ja/types.comparisons.php
動作確認
http://codepad.org/Cgl6apJa

|value|memo|gettype()|!empty()|(bool)|!!|isset()|!is_null()|
|:--|:--|:--|:--|:--|:--|:--|:--|
|true||boolean|1|1|1|1|1|
|false||boolean|0|0|0|1|1|
|1||integer|1|1|1|1|1|
|0||integer|0|0|0|1|1|
|1.0||double|1|1|1|1|1|
|0.0||double|0|0|0|1|1|
|'1'||string|1|1|1|1|1|
|'0'||string|0|0|0|1|1|
|"1"||string|1|1|1|1|1|
|"0"||string|0|0|0|1|1|
|'1.0'||string|1|1|1|1|1|
|'0.0'||string|1|1|1|1|1|
|"1.0"||string|1|1|1|1|1|
|"0.0"||string|1|1|1|1|1|
|''||string|0|0|0|1|1|
|""||string|0|0|0|1|1|
|array()||array|0|0|0|1|1|
|null||NULL|0|0|0|0|0|
|$a|未定義の変数|NULL|0|0 (Noticeが出る)|0 (Noticeが出る)|0|0 (Noticeが出る)|
|function() {}|php 5.3 以降|object|1|1|1|1|1|

#### まとめ
* シングルクォートとダブルクォートの判定の差はない
* `!empty()`と`(bool)`と`!!`の判定はほぼ同じ
    * `(bool)`と`!!`は同じ
        * というか、PHPの`if`の中では内部的にbool型に変換して解釈してる
    * `(bool)`と`!!`は未定義の変数に対して使うとPHP Notice:  Undefined variableで怒られる
    * **「文字列の0.0」はtrueになる**
        * 文字列の0.0をfalseで判定させる機会は少ないと思われるが、一応気にかけておくこと
* `isset()`と`!is_null()`の判定はほぼ同じ
    * `!is_null()`は未定義の変数に対して使うとPHP Notice:  Undefined variableで怒られる
* phpで空判定をしたい時は`empty()`か`isset()`を使うのが無難
* `isset()`は「変数にnull以外の何かが入っていたらtrue」
* `empty()`は「0っぽい時(長さとか)はtrue」
* **`isset()`と`empty()`は言語構造なのでPHP Noticeが出ない**

#### まとめ追記
`array_key_exists()`も、配列の空チェックにおいて重要になので追記。
http://codepad.org/IUs7iFdD

以下の構造に対してチェックした結果

```
$check_list = array(
    'a' => 0,
    'b' => '',
    'c' => null,
//    'd' => null,
);
```
|key|!empty()|isset()|array_key_exists()|
|:--|:--|:--|:--|
|'a'|false|true|true|
|'b'|false|true|true|
|'c'|false|false|true|
|'d'|false|false|false|

重要なのは中身が`null`のkeyの`isset()`が`false`になることです。
keyが有る無しのチェックはキチンと`array_key_exists()`を使って、中身の有る無しのチェックは`!empty()`か`isset()`を使いましょう。

## Javascriptの場合
#### 空チェックリスト
FireFox 33.0 と Chrome 38.0.2125.104 m で確認。
下の表で`toString.call()`と書かれている部分は、`Object.prototype.toString.call()`で確認した結果。
`notEmpty()`は自作関数、ページの下の方で解説します。

|value|typeof|toString.call()|Boolean()|!!|notEmpty()|
|:--|:--|:--|:--|:--|:--|
|true|boolean|[object Boolean]|true|true|true|
|false|boolean|[object Boolean]||||
|1|number|[object Number]|true|true|true|
|0|number|[object Number]||||
|1.0|number|[object Number]|true|true|true|
|0.0|number|[object Number]||||
|'1'|string|[object String]|true|true|true|
|'0'|string|[object String]|true|true||
|"1"|string|[object String]|true|true|true|
|"0"|string|[object String]|true|true||
|'1.0'|string|[object String]|true|true|true|
|'0.0'|string|[object String]|true|true||
|"1.0"|string|[object String]|true|true|true|
|"0.0"|string|[object String]|true|true||
|''|string|[object String]||||
|""|string|[object String]||||
|undefined|undefined|[object Undefined]|||
|null|object|[object Null]||||
|[]|object|[object Array]|true|true||
|{}|object|[object Object]|true|true||
|function() {}|function|[object Function]|true|true|true|

#### まとめ
* シングルクォートとダブルクォートの判定の差はない
* `Boolean()`と`!!`の判定は同じ
* `typeof`で調べると、null、array、objectが全部objectと判定される
    * `Object.prototype.toString.call()`で調べると、ちゃんとした型がわかる
* 真偽値と数値の判定はPHPと同じ
* 文字列は中に空文字以外が入ってたら全部trueになっちゃう
    * 0文字列を弾きたかったら別途対応する
* 配列とオブジェクト(連想配列)は全部true
    * 空配列を弾きたかったら、別途対応する

#### JSでPHPの!emptyっぽい挙動対応版
JSでも0文字列と空配列を弾きたかったので、作ってみた。

```js:not_empty.js
function notEmpty(value) {
    var result;
    switch (typeof value) {
    case 'string':
        // 文字の0を除く
        result = (value && value != 0);
        break;
    case 'object':
        // 配列の中身の数チェック
        result = (value && Object.keys(value).length);
        break;
    default:
        result = value;
    }
    return Boolean(result);
}
```

三項演算子を使った1行ver。

```js:not_empty_min.js
function notEmpty(v) {
    return Boolean(
        typeof v == 'string' ?
            v && v != 0 :
        typeof v == 'object' ?
            v && Object.keys(v).length :
            v
    );
}
```
* 文字列の0対応
    * `result = (value && value != 0);`
        * `value != 0`のところで文字列0をfalseにする
        * PHPと違って文字列0.0もfalseにするけど、むしろその方が自然な気がするので気にしないことにする
* 空配列対応
    * `result = (value && Object.keys(value).length);`
    * `Object.keys(value).length`のところでオブジェクトのkeyのリストを取得して、その長さを出している
        * 長さが0で無ければok
        * 配列もオブジェクトも`Object.keys(value).length`で項目の数がわかる
    * `Object.keys(null)`はnon-objectとか言われるので、先に最初の`value`のところでfalse判定して弾いている