Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

先日、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"の両方作って、スペースのみを振り分けよう
  • "タブのみ"って空とすべきなのか・・・?
hirossyi73
株式会社カジトリ 代表取締役社長。 OSSなLaravelのWebデータベース「Exment」、C#・Python・PHP開発、WordPressによる個人サイト作成をはじめとして、幅広い開発を手がけています。 最近電子書籍を発行しました。Amazon Kindleストアで「ぽんこつエンジニア」で検索。
https://kajitori.co.jp
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