無料Wikiサービス | デモページ
Linuxなどのメモ書き

PHP is_numeric()と整数


概要

PHPには変数が数値形式(int型/float型/数値表記のstring)かどうかを調べるis_numeric()という便利な関数がある。この関数は、実数形式もtrueとなるのだが、整数形式だけをtrue判定したい場合もよくある。ただ、このような関数は提供されていないので作成する(*1)。

(*1) is_int()はint型かどうかを判定するもので'10'(文字列の'10')はfalseになるので、今回の要求は満たさない。

is_numeric_int()

関数名は適当だが、is_numeric()のうち整数形式のものだけtrueを返すということでis_numeric_int()とする。

is_numeric_int()

function is_numeric_int($var)
{
    if (is_int($var)) {
        return true;
    }
    if (is_string($var)) {
        return filter_var($var, FILTER_VALIDATE_INT) !== false;
    }
    return false;
}

 

テストコード

function dump_result($title, $value, $expected)
{
    printf("%-15s %-8s %s\n",
           $title,
           $value ? 'true' : 'false',
           ($expected === $value) ? 'OK' : 'NG');
}

function test()
{
    $testCases = [
        // int
        ['title' => "10",   'value' => 10,   'return' => true],
        ['title' => "0x1a", 'value' => 0x1a, 'return' => true],
        ['title' => "-10",  'value' => -10,  'return' => true],
        ['title' => "0",    'value' => 0,    'return' => true],
        // float
        ['title' => "10.1", 'value' => 10.1, 'return' => false],
        ['title' => "10.0", 'value' => 10.0, 'return' => false], // 小数点以下が0のケース
        ['title' => "123.45e6",  'value' => 123.45e6,  'return' => false],
        ['title' => "123.45e-4", 'value' => 123.45e-4, 'return' => false],

        // string
        ['title' => "'10'",   'value' => '10',   'return' => true],
        ['title' => "'-10'",  'value' => '-10',  'return' => true],
        ['title' => "'0'",    'value' => '0',    'return' => true],
        ['title' => "'10.1'", 'value' => '10.1', 'return' => false],
        ['title' => "'10.0'", 'value' => '10.0', 'return' => false],
        ['title' => "'123.45e6'",  'value' => '123.45e6',  'return' => false],
        ['title' => "'123.45e-4'", 'value' => '123.45e-4', 'return' => false],
        ['title' => "'0x1a'", 'value' => '0x1a', 'return' => false],
        ['title' => "'foo'",  'value' => 'foo',  'return' => false],
        ['title' => "'10 is int'", 'value' => '10 is int', 'return' => false],
        ['title' => "''",   'value' => '', 'return' => false],
        // other types
        ['title' => "null",   'value' => null,  'return' => false],
        ['title' => "true",   'value' => true,  'return' => false],
        ['title' => "false",  'value' => false, 'return' => false],
        ['title' => "array",  'value' => [],    'return' => false],
        ['title' => "object", 'value' =>(object) ['foo' => 'bar'], 'return' => false],
    ];

    printf("input           return   result\n");
    foreach ($testCases as $case) {
        dump_result($case['title'], is_numeric_int($case['value']), $case['return']);
    }
}
test();

 

テスト結果

input           return   result
10              true     OK
0x1a            true     OK
-10             true     OK
0               true     OK
10.1            false    OK
10.0            false    OK
123.45e6        false    OK
123.45e-4       false    OK
'10'            true     OK
'-10'           true     OK
'0'             true     OK
'10.1'          false    OK
'10.0'          false    OK
'123.45e6'      false    OK
'123.45e-4'     false    OK
'0x1a'          false    OK
'foo'           false    OK
'10 is int'     false    OK
''              false    OK
null            false    OK
true            false    OK
false           false    OK
array           false    OK
object          false    OK

10.0とか123.45e6は結果は整数と同じだが、あくまで実数形式ということでfalseを返す。

 

まとめ

なぜこんなことを書いたかというと、同様の判定処理をワンライナー等でやろうとして、正しく判定できていないケースをたまに見かけるため。

例えば filter_var($var, FILTER_VALIDATE_INT)のみで判定しているケース。

正しく判定できていない処理

function is_numeric_int($var)
{
    return filter_var($var, FILTER_VALIDATE_INT) !== false;
}

結果

input           return   result
10              true     OK
0x1a            true     OK
-10             true     OK
0               true     OK
10.1            false    OK
10.0            true     NG
123.45e6        true     NG
123.45e-4       false    OK
'10'            true     OK
'-10'           true     OK
'0'             true     OK
'10.1'          false    OK
'10.0'          false    OK
'123.45e6'      false    OK
'123.45e-4'     false    OK
'0x1a'          false    OK
'foo'           false    OK
'10 is int'     false    OK
''              false    OK
null            false    OK
true            true     NG
false           false    OK
array           false    OK
object          false    OK

10.0(float),123.45e6(float),true(boolean)が整数判定されているのがわかる。これはfilter_var()の第一引数は内部でstring型に変換されるのが原因。10.0や123.45e6は変換結果が整数表記になるので整数扱いされる。trueは'1'に変換されるため、これも整数扱いされてしまう。

$varの型がstring型に限定されるのであれば、上記処理でも正常に判定できるが、任意の型に対しては正しく判定できていないのがわかる。任意の型に対して判定したいのなら、ワンライナーは諦めて愚直にチェックした方がよい。

 


最終更新 2017/07/09 23:19:11 - kztomita
(2017/07/09 23:02:41 作成)