PHP7から、スカラ型(int
、float
、string
、bool
)のタイプヒントが書けるようになります。関数の引数だけでなく、返り値にも書けます(参照:「PHP7調査(35)関数の返り値のタイプヒントが書けるようになった - Qiita」)。
話がややこしくなるので本稿ではstrict modeには触れず、デフォルトの挙動であるweak modeの話題のみを扱います。
スカラ型のタイプヒントの記法
スカラ型のタイプヒントは他の型のタイプヒントと同じように記述することができます。
<?php
function foo(int $i) { var_dump($i); }
foo(3); /* int(3) */
タイプヒントで新たに書けるようになった型はint
、float
、string
、bool
の4つだけです。mixed
のような指定はできません。
スカラ型のタイプヒントと型キャスト
スカラ型のタイプヒントはクラスなどのタイプヒントとは異なり、必要に応じてキャストされます。
<?php
function foo(int $i) { var_dump($i); }
foo(10.0); /* int(10) */
foo("1e3"); /* int(1000) */
int
型のタイプヒントに対してfloat
型やdouble
型の値を渡すとキャストされることがわかります。
この型キャストのルールは組み込み関数での型キャストとほとんど同じということになっています。型キャストの詳細は次のような表にまとめることができます。
タイプヒント\実際の型 | int | float | string | bool | object |
---|---|---|---|---|---|
int | yes | yes★ | yes★† | yes | no |
float | yes☆ | yes | yes† | yes | no |
string | yes | yes | yes | yes | yes‡ |
bool | yes | yes | yes | yes | no |
- ☆:64bit環境で53bit以上の整数を渡した場合に精度が落ちることがある、エラーは特に出ない
- ★:浮動小数点数の値が整数の範囲内のときはキャストされる。そうでなければ
TypeException
がスローされる(参照:PHP7調査(5)整数型の引数のオーバーフローがエラーになった - Qiita) - †:数値文字列であればキャストされる。文字列の先頭が数値文字列として解釈できる場合は、noticeを出した上で残りを無視してキャストされる。数値文字列でない場合は
TypeException
がスローされる。 - ‡:オブジェクトが
__toString
メソッドを持っているときのみキャストされる。それ以外の場合TypeException
がスローされる。
nullの扱いの違い
実は、ユーザー関数の型キャストのルールは組み込み関数での型キャストとでnull
に関する挙動だけが異なっています。次の例を見てみましょう。
<?php
var_dump(array_fill(null, 3, "foo"));
/*
array(3) {
[0]=>
string(3) "foo"
[1]=>
string(3) "foo"
[2]=>
string(3) "foo"
}
*/
array_fill()
の第1引数はint
型ですが、null
を渡してもエラーにはならず、0として解釈されていることがわかります。一方でユーザー関数の場合は挙動が異なります。
<?php
function my_array_fill(int $start_index, int $num, $value) {
return array_fill($start_index, $num, $value);
}
var_dump(my_array_fill(null, 3, "foo"));
/*
PHP Fatal error: Uncaught TypeException: Argument 1 passed to my_array_fill() must be of the type integer, null given, called in /tmp/cast-with-userfunc.php on line 5 and defined in /tmp/cast-with-userfunc.php:2
Stack trace:
#0 /tmp/cast-with-userfunc.php(5): my_array_fill(NULL, 3, 'foo')
#1 {main}
thrown in /tmp/cast-with-userfunc.php on line 2
*/
このように、ユーザー関数のタイプヒントではnull
は勝手にはキャストされず、エラーになります。引数のデフォルト値をnull
に指定するとnull
を許容しますが、当然ながらキャストはされません。クラスなどのタイプヒントの挙動と整合性を取るため、このような仕様になっています。
型のエイリアス名はタイプヒントに使えない
経緯は追っていませんが、integer
・double
・boolean
の3つの型名はタイプヒントに利用できません。これらをタイプヒントに指定すると、PHP5までと同様にクラス名として解釈されます。このままの仕様だとPHPプログラマが混乱しかねないので、エラーメッセージを整理すべきかもしれません。
PHP Fatal error: Uncaught TypeException: Argument 1 passed to foo() must be an instance of integer, integer given, called in /tmp/foo.php on line 3 and defined in /tmp/foo.php:2
Stack trace:
#0 /tmp/foo.php(3): foo(3)
#1 {main}
thrown in /tmp/foo.php on line 2
「第1引数はinteger
のインスタンスであるべきなのにinteger
が渡された!」「お、おう…?」