開発室ブログ

PHP

PHPの真偽・空判定まとめ

PHPでコード書いてて、if文で「あれ!?これって通っちゃう!?」と気になって、値を返すメソッドを見直したりで、肝心な実行コードに進めなくなることありますよね?

え?! ありませんか?

まぁ、「テスト」を先に書くプロジェクトなんかでしたら無いでしょうけど・・・
気付かず(気にせず)書き進めてテストしたら思わぬ結果に・・・とかなら良くありますけどね(私の場合ですけど)

真偽(TRUE or FALSE)を返す関数は無数にありますけど、今回は演算子や基本的な関数でしっかり判定するために、一通り試してみたいと思います。

(そのまま判定)

まず、if文の条件反映に変数をそのまま突っ込んでみます。 自然言語的に言えば、「この変数良い?ダメ?」くらいの曖昧さですね。

if文の中で使うことを想定してますので、Booleanにキャストしてから結果を出力します)

<?php
$vars = ['', null, true, false, 0, "0", 1, "1", 'variable', [], [0]];
foreach($vars as $var) {
var_dump((bool) $var);
}

結果

bool(false) // ''
bool(false) // NULL
bool(true) // true
bool(false) // false
bool(false) // 0
bool(false) // '0'
bool(true) // 1
bool(true) // '1'
bool(true) // 'variable'
bool(false) // array ( )
bool(true) // array ( 0 => 0, )

意外と「自然」です(笑)
false.null,''(空),0,’0',[](空配列)を弾きました。
この挙動を正確に把握しているプログラマにとっては、使い所があり、使い勝手も悪くないんでしょうが、コードチェックの際に「曖昧すぎ」とコメントを貰う事になりそうです。

!

次に、!です。
自然言語で言えば「じゃない時」ですね。
通常は「変数の値が”真”じゃない時」の判定で使用します。

<?php
$vars = ['', null, true, false, 0, "0", 1, "1", 'variable', [], [0]];
foreach($vars as $var) {
var_dump(! $var);
}

上記の結果は・・・

bool(true) // ''
bool(true) // NULL
bool(false) // true
bool(true) // false
bool(true) // 0
bool(true) // '0'
bool(false) // 1
bool(false) // '1'
bool(false) // 'variable'
bool(true) // array ( )
bool(false) // array ( 0 => 0, )

''(空)でもnullでも通りますw
あと、文字列数値の'0'でも通るのがポイント。
曖昧なので、通常はこれ単体では使う事はあまり無いと思います。

比較演算子!==!=

3字の方は「型」まで比較します。 例えば「1」と「’1’」の比較が「偽」になります。

<?php
$vars = ['', null, true, false, 0, "0", 1, "1", 'variable', [], [0]];
foreach($vars as $var) {
var_dump(false !== $var);
}
---
foreach($vars as $var) {
var_dump(false != $var);
}

結果

bool(true) // ''
bool(true) // NULL
bool(true) // true
bool(false) // false
bool(true) // 0
bool(true) // '0'
bool(true) // 1
bool(true) // '1'
bool(true) // 'variable'
bool(true) // array ( )
bool(true) // array ( 0 => 0, )
---
bool(false) // ''
bool(false) // NULL
bool(true) // true
bool(false) // false
bool(false) // 0
bool(false) // '0'
bool(true) // 1
bool(true) // '1'
bool(true) // 'variable'
bool(false) // array ( )
bool(true) // array ( 0 => 0, )

3字の方はfalse以外は「真」になるのに対して、2字の方は''(空),null,0,'0',[](空配列)が「偽」になってしまいます。
単純な文字列比較以外で2字演算子での真偽判定は避けるべきなのがわかります。

(因みに、否定じゃない方=====については、結果を省きます。わかると思うので・・・)

関数 isset()

真偽判定でよく使う関数isset()。変数が定義されているか否かを判別しますが、落とし穴があります。

<?php
$vars = ['', NULL, TRUE, FALSE, 0, "0", 1, "1", [] ,[0]];
foreach($vars as $var) {
var_dump(isset($var));
}

結果

bool(true) // ''
bool(false) // NULL
bool(true) // true
bool(true) // false
bool(true) // 0
bool(true) // '0'
bool(true) // 1
bool(true) // '1'
bool(true) // array ( )
bool(true) // array ( 0 => 0, )

値がnullだと「偽」になります! なお、「空」でも「真」となりますが、「定義されているか否か」なので、当然答えは「真」なのです。ならば、値がnullでも「真」で良いような気が・・・
フォームから送られてきた値を処理する時なんか、空の変数が発生しがちですが、判定を誤ると空メールが送られたり・・・というバグの元と考えられますね。

関数 empty()

こちらも真偽判定でよく使う関数empty()です。
変数の値が「空」であるか否かを判別します。

<?php
$vars = ['', NULL, TRUE, FALSE, 0, "0", 1, "1", [] ,[0]];
foreach($vars as $var) {
var_dump(empty($var));
}

結果

bool(true) // ''
bool(true) // NULL
bool(false) // true
bool(true) // false
bool(true) // 0
bool(true) // '0'
bool(false) // 1
bool(false) // '1'
bool(true) // array ( )
bool(false) // array ( 0 => 0, )

注意しなければならないのが、 文字列数値の'0'も「真」と判定する点。 使い勝手が良い点は、空の配列を「真」としてくれる点で、個人的には、いちばん良く使う関数です。
例えば、

if (! empty($var)) {
// Do something
}

とすると、変数の値がfalse.null,''(空),0,'0',[](空配列)を弾いてくれます。

関数is_null()

文字通り、「変数の値がnullの場合”真”」ですが、本当にそうなるのでしょうか・・・?

bool(false) // ''
bool(true) // NULL
bool(false) // true
bool(false) // false
bool(false) // 0
bool(false) // '0'
bool(false) // 1
bool(false) // '1'
bool(false) // array ( )
bool(false) // array ( 0 => 0, )

なります(笑)
しかし、nullしか判定しないので、実際の現場ではDBからの返り値を検証する時以外は使わない気がします。

その他

is_~系の関数では、is_​array(), is_​bool(), is_​callable(), is_​double(), is_​float(), is_​int(), is_​integer(), is_​numeric(), is_​object(), is_​real(), is_​resource(), is_​scalar(), is_​string()等が存在します。
これらは殆ど変数の値が持つ「型」の判定に使います。

is_​int()is_​numeric()の違い

両方とも「数値であるか否か」に使われがちですが、

$vars = [0, "0", 1, "1", '123456', 123456, 123.456, '123.456'];
foreach($vars as $var) {
var_dump(is_int($var));
echo ' // ';
var_export($var);
echo '<br>';
}
---
foreach($vars as $var) {
var_dump(is_numeric($var));
echo ' // ';
var_export($var);
echo '<br>';
}

結果

bool(true) // 0
bool(false) // '0'
bool(true) // 1
bool(false) // '1'
bool(false) // '123456'
bool(true) // 123456
bool(false) // 123.456
bool(false) // '123.456'
---
bool(true) // 0
bool(true) // '0'
bool(true) // 1
bool(true) // '1'
bool(true) // '123456'
bool(true) // 123456
bool(true) // 123.456
bool(true) // '123.456'

となります。
is_int()ではその名の通り、「Integerであるか否か」を判別しますので、文字列数値も小数ですらも弾かれます。
因みにPHPではPost或いはGetで渡された値は、元がどうあれ文字列数値にコンバートされますので注意が必要です。

配列の空判定

先程のempty()関数で空配列を判定出来ましたが、中身が配列であるのが間違いない変数に使うのは無粋です(チーム開発の現場では、コードレビュー時にコーディングした側の意図が見えにくいので避けたい)。
そんな時、配列の中身の数を数えたり(count())、配列の中身の合計値(array_sum())で判別したように書くことがよく有ります。

$vars = [[], [''], [0], [1], ['foo'=> 1], ['foo'=>'var']];
foreach($vars as $var) {
var_dump(count($var) > 0);
}
---
foreach($vars as $var) {
var_dump(array_sum($var) > 0);
}

結果

bool(false) // array ( )
bool(true) // array ( 0 => '', )
bool(true) // array ( 0 => 0, )
bool(true) // array ( 0 => 1, )
bool(true) // array ( 'foo' => 1, )
bool(true) // array ( 'foo' => 'var', )
---
bool(false) // array ( )
bool(false) // array ( 0 => '', )
bool(false) // array ( 0 => 0, )
bool(true) // array ( 0 => 1, )
bool(true) // array ( 'foo' => 1, )
bool(false) // array ( 'foo' => 'var', )

count()は配列の中に「ゴミ」が入ってしまうと「真」になりますので注意が必要です。
array_sum()を使う場合は、あくまで「合計」なので、ハッシュ(キー付き配列)で値に数値が存在し得ない場合は利用出来ない事に注意が必要です。

「一旦、array_map()で値を(Int)でキャストして~」とか、この先のネタは尽きませんが、制御の為ではなく主に空判定の場合であり、レビュアーに対しての「ちゃんと考えて書いてるよ~」というブラフのようなものなので、この辺でお終いにします(笑)

まとめ

($var) (!$var) (false!==$var) (false!=$var) isset($var) empty($var) is_null($var)
'' false true true false true true false
null false true true false false true true
true true false true true true false false
false false true false false true true false
0 false true true false true true false
'0' false true true false true true false
1 true false true true true false false
'1' true false true true true false false
'variable' true false true true true false false
[] false true true false true true false
[0] true false true true true false false

私がif文でよく使う条件を羅列しただけ、、、になってしまった感がありますし、結局はプロジェクトや成果物の内容によって、これらを「組み合わせながら」使うことになります。
(コレ以外使わなくてOK!的な記述を期待されていた方、スミマセン。イメージ的には、もう少し面白味のある記事になる予定だったんだけどなぁ~)

以上、今回は写真も引用もない記事をお送りしました~

RecentPost