22
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHP7調査(36)スカラ型のタイプヒントが書けるようになった

Last updated at Posted at 2015-05-24

PHP7から、スカラ型(intfloatstringbool)のタイプヒントが書けるようになります。関数の引数だけでなく、返り値にも書けます(参照:「PHP7調査(35)関数の返り値のタイプヒントが書けるようになった - Qiita」)。

話がややこしくなるので本稿ではstrict modeには触れず、デフォルトの挙動であるweak modeの話題のみを扱います。

スカラ型のタイプヒントの記法

スカラ型のタイプヒントは他の型のタイプヒントと同じように記述することができます。

<?php
function foo(int $i) { var_dump($i); }
foo(3); /* int(3) */

タイプヒントで新たに書けるようになった型はintfloatstringboolの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に関する挙動だけが異なっています。次の例を見てみましょう。

cast-with-sysfunc.php
<?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として解釈されていることがわかります。一方でユーザー関数の場合は挙動が異なります。

cast-with-userfunc.php
<?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を許容しますが、当然ながらキャストはされません。クラスなどのタイプヒントの挙動と整合性を取るため、このような仕様になっています。

型のエイリアス名はタイプヒントに使えない

経緯は追っていませんが、integerdoublebooleanの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が渡された!」「お、おう…?」

参照

22
19
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?