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