Edited at

【PHP】is_nullもissetもemptyも絶妙に微妙なので、"is_nullorempty"を自作しよう


はじめに

先日、Twitterでこんな投稿をしました。

今回はこの話を、もう少し掘り下げて話を進めていきたいと思います。


isset, empty, is_nullどれも絶妙に微妙

PHPのnull・空判定には、主に「isset, empty, is_null」の3つが用意されています。

しかし、これらの関数は、私にとって絶妙に微妙でした。

まずは、これらの関数の結果を改めて見てみます。なおPHP isset, empty, is_null の違い早見表からの引用です。


if($var)
isset
empty
is_null

$var=1
true
true
false
false

$var="";
false
true
true
false

$var="0";
false
true
true
false

$var=0;
false
true
true
false

$var=NULL;
false
false
true
true

$var
false
false
true
true

$var=array()
false
true
true
false

$var=array(1)
true
true
false
false


空判定したい時は、「入力チェックを行いたい時」

さて、皆さんがこれらの空判定関数を使用したい時は、主にどんな状況でしょうか?

色々あると思いますが、私が思うもっとも頻出な場面として、

ユーザーやシステムが、値を入力したかどうかの必須チェックを行う

時だと思います。

ユーザーの画面入力、CSVからの取込やデータベースからのデータ取得など、多くの場面で出てくる、「値の有無チェック」。

そのような前提を考えた時、上記の3関数だと、実はどれも絶妙にマッチしないんです。

なので、このような入力チェックで完全に判定できるような関数、「is_nullorempty」を作成しよう!というのが、今回の目的です。

※issetとemptyは厳密には関数じゃないらしいですが、ここでは関数としちゃいます


空判定したい内容の分析

ここからは、各値ごとに、「空判定すべきかどうか」のあるべき姿の分析を行っていきます。この値は空としたいかどうか?という判断ですね。

実際に入力チェックを行った時に、この値は空にしたいかどうか?という観点で見ていきます。

※なお、ここでは「空」は、「値がない」ということを指します。

またこれ以降、空として扱いたい場合は"空とする"と、空として扱いたくない場合は"空としない"と記載していきます。


■ null

これは間違いなく"空とする"ですね。


■ 空文字""

CSVやExcel取込などでよく発生する、「空文字""」の場合。

関数issetだとtrueになる("空としない"となる)この値ですが、これは間違いなく"空とすべき"でしょう。

ユーザーが何も入力していないから、空文字となって返ってくるわけです。そのため、空文字は"空とする"として考えます。


■ 0

関数emptyだとtrueになる("空とする"となる)この値ですが、これはどうでしょうか?

ユーザーが「0」と入力した時、CSVに「0」と入力されていた時。これは「未入力」として扱うべきでしょうか。違うと思います。

そのため、0は"空としない"として考えます。もちろん文字列"0"も同様です。


■ array()

要素がない配列。これはユーザーやシステムが値をちゃんと入れていないから、要素数が0の配列が出来ているわけです。

そのため、要素数0の配列は"空とする"として考えます。


■ " "(半角スペース)、ならびに" "(全角スペース)のみの文字列

さて半角・全角スペースのみの文字列。これはどうでしょうか。これに関しては判断が迷いそうです。

これは私の考え方ですが、状況によりけりだと考えます。常に"空とする"としても、"空としない"としても、場合によって色々と異なってきそうです。

そこでどうするかというと、スペースのみを"空としない"とする"is_nullorempty"と、"空とする"とする"is_nullorwhitespace"の両方を作ってしまっていいと考えます。

両方作った上で、「基本はこちらを使用する」というルールを決めてしまう。もしくは、あえてどちらかしか実装しない。という方針が良いと思います。

ちなみにこの関数名ですが、C#から来ています。String.IsNullOrEmptyString.IsNullOrWhiteSpaceがあります。


空判定まとめ

これが私の考える、空判定のあるべき姿です。


is_nullorempty
is_nullorwhitespace

$var=1
false
false

$var="";
true
true

$var="0";
false
false

$var=0;
false
false

$var=NULL;
true
true

$var
-
-

$var=array()
true
true

$var=array(1)
false
false

$var=" "
false
true

$var=" "
false
true

※"$var"について、undefinedな変数を関数に代入した時点でエラーになっちゃうので、判定できません。そこだけは欠点ですね


実装

では実装に入りたいと思います。

なお実装方法については、もっといい方法がありそうです(・∀・)

<?php

if (!function_exists('is_nullorempty')) {
/**
* validate string. null is true, "" is true, 0 and "0" is false, " " is false.
*/

function is_nullorempty($obj)
{
if($obj === 0 || $obj === "0"){
return false;
}

return empty($obj);
}
}

if (!function_exists('is_nullorwhitespace')) {
/**
* validate string. null is true, "" is true, 0 and "0" is false, " " is true.
*/

function is_nullorwhitespace($obj)
{
if(is_nullorempty($obj) === true){
return true;
}

if(is_string($obj) && mb_ereg_match("^(\s| )+$", $obj)){
return true;
}

return false;
}
}

/**
* テスト用
*
* @param [type] $value
* @return void
*/

function strbool($value)
{
return $value ? 'true' : 'false';
}

// テスト。ザル
echo('is_nullorempty "foo" is ' . strbool(is_nullorempty("foo")));
echo('<br />is_nullorempty 1 is ' . strbool(is_nullorempty(1)));
echo('<br />is_nullorempty "" is ' . strbool(is_nullorempty("")));
echo('<br />is_nullorempty "0" is ' . strbool(is_nullorempty("0")));
echo('<br />is_nullorempty 0 is ' . strbool(is_nullorempty(0)));
echo('<br />is_nullorempty NULL is ' . strbool(is_nullorempty(null)));
echo('<br />is_nullorempty array() is ' . strbool(is_nullorempty(array())));
echo('<br />is_nullorempty array(1) is ' . strbool(is_nullorempty(array(1))));
echo('<br />is_nullorempty " " is ' . strbool(is_nullorempty(" ")));
echo('<br />is_nullorempty " " is ' . strbool(is_nullorempty(" ")));
echo('<br />');
echo('<br />is_nullorwhitespace "foo" is ' . strbool(is_nullorwhitespace("foo")));
echo('<br />is_nullorwhitespace 1 is ' . strbool(is_nullorwhitespace(1)));
echo('<br />is_nullorwhitespace "" is ' . strbool(is_nullorwhitespace("")));
echo('<br />is_nullorwhitespace "0" is ' . strbool(is_nullorwhitespace("0")));
echo('<br />is_nullorwhitespace 0 is ' . strbool(is_nullorwhitespace(0)));
echo('<br />is_nullorwhitespace NULL is ' . strbool(is_nullorwhitespace(null)));
echo('<br />is_nullorwhitespace array() is ' . strbool(is_nullorwhitespace(array())));
echo('<br />is_nullorwhitespace array(1) is ' . strbool(is_nullorwhitespace(array(1))));
echo('<br />is_nullorwhitespace " " is ' . strbool(is_nullorwhitespace(" ")));
echo('<br />is_nullorwhitespace " " is ' . strbool(is_nullorwhitespace(" ")));

// テスト結果
// is_nullorempty "foo" is false
// is_nullorempty 1 is false
// is_nullorempty "" is true
// is_nullorempty "0" is false
// is_nullorempty 0 is false
// is_nullorempty NULL is true
// is_nullorempty array() is true
// is_nullorempty array(1) is false
// is_nullorempty " " is false
// is_nullorempty " " is false
//
// is_nullorwhitespace "foo" is false
// is_nullorwhitespace 1 is false
// is_nullorwhitespace "" is true
// is_nullorwhitespace "0" is false
// is_nullorwhitespace 0 is false
// is_nullorwhitespace NULL is true
// is_nullorwhitespace array() is true
// is_nullorwhitespace array(1) is false
// is_nullorwhitespace " " is true
// is_nullorwhitespace " " is true
?>


まとめ


  • 値の入力チェックは、基本3関数どれも微妙なので、自作の関数を作ろう

  • "is_nullorempty"と"is_nullorwhitespace"の両方作って、スペースのみを振り分けよう

  • "タブのみ"って空とすべきなのか・・・?