PHP7では、組み込み関数の整数型引数に整数で表現できない値を渡した場合にエラーになります。
<?php
var_dump(array_fill(10000000000000000000, 3, "foo"));
<?php
var_dump(array_fill("10000000000000000000", 3, "foo"));
これらを実行すると次のようなエラーが帰ってきます。
PHP Warning: array_fill() expects parameter 1 to be integer, string given in /tmp/string1.php on line 2
NULL
PHP Warning: array_fill() expects parameter 1 to be integer, float given in /tmp/float1.php on line 2
NULL
array_fillの第一引数はint型ですが(PHPマニュアルの「array_fill」参照)、これに整数以外の値を渡してエラーになっているのがわかります。
これはint型のタイプヒントの場合も同様です。
<?php
function foo(int $i) {}
foo(10000000000000000000);
PHP Fatal error: Uncaught TypeException: Argument 1 passed to foo() must be of the type integer, float given, called in /tmp/float2.php on line 3 and defined in /tmp/float2.php:2
Stack trace:
#0 /tmp/float2.php(3): foo(1E+19)
#1 {main}
thrown in /tmp/float2.php on line 2
こうしたエラーメッセージを見ると浮動小数点数や文字列を渡したせいで怒られているように見えますが、実際には整数にキャストできない値を渡したせいで怒られています。具体的には、[PHP_INT_MIN, PHP_INT_MAX]の範囲外だと怒られます。
下記のように、整数の範囲内であれば浮動小数点数や文字列を渡しても期待通りに動きます。
<?php
var_dump(array_fill(1.9, 3, "foo"));
/*
array(3) {
[1]=>
string(3) "foo"
[2]=>
string(3) "foo"
[3]=>
string(3) "foo"
}
*/
<?php
var_dump(array_fill("1e10", 3, "foo"));
/*
array(3) {
[10000000000]=>
string(3) "foo"
[10000000001]=>
string(3) "foo"
[10000000002]=>
string(3) "foo"
}
*/
ちなみにPHP5までは、整数の範囲外の値を持つ浮動小数点数を整数にキャストした場合の挙動は未定義でした。実際に手元で試してみると非常に小さな整数にキャストされます。
$ php56 -r 'var_dump(array_fill(NAN, 3, "foo"));'
array(3) {
[-9223372036854775808]=>
string(3) "foo"
[0]=>
string(3) "foo"
[1]=>
string(3) "foo"
}
これに対応するPHP5のCソースコードを見ると、単にdoubleからlongにキャストするような処理になっています。このようなキャストでdoubleがlongの範囲外の場合の挙動はC言語として未定義で、結果は処理系依存・環境依存ということになります。Cレベルで未定義の挙動をPHPプログラマに提供してきたこと自体が残念仕様だったと思いますので、今回の修正は当然とも言えるでしょう。
# 参考