phpの型宣言(タイプヒンティング)|nullとかオブジェクトとか色々調べたみた

今日ボーっとtwitterを眺めていると、面白いツイートを見つけた。

function print_count(int $count) {
echo "チョコを{$count}個もらいました";
}

という関数を

print_count('1個もチョコ、もらえませんでした');

で呼び出すと「チョコを1個もらいました」と出力してくれるPHPは優しかった。

— suin❄️PHPでオブジェクト指向 (@suin) February 14, 2019

最近phpをやり始めたばかりなので、phpで型宣言ができるとは知らなかった。(php5までは「型宣言」のことは「タイプヒンティング」と呼んでいた。参考:PHP: 関数の引数 - Manual

そこで今日は、phpの型宣言について色々調べてみたよ。

phpの型宣言(タイプヒンティング)とは?

phpの型宣言とは、名前の通り関数の引数の型を指定できる機能のこと。

例えば、以下のコードの様に関数の引数をint $numと書いてあげることで、引数にはinteger型のみ受け付けるようにできる。

<?php
function mult_two(int $num) {
return $num * 2;
}
echo mult_two(2);
?>

そもそも、型宣言をすると何が嬉しいかと言うと、以下の2点が挙げられる。

  • 本来期待している型と異なる型が引数に格納されることで起こる、思わぬバグを防げる
  • コードが読みやすくなる。

例えば、$numにはinteger型が入ってほしいけど間違えてstring型を入れてしまった場合等は、型宣言をしておくことでエラーを表示してくれるので、間違いに気付きやすくなる。

また、他人のコードを読む作業は疲れるものだが、関数の引数と戻り値の型が分かるだけでも読みやすさが違ってくるので、型を明示するのは良い。(コメントとしても書くけど)

phpにはどんな型宣言(タイプヒンティング)ができるか?

phpでは、以下の9つの型宣言を行える。(php7.3時点)

php 5.0.0から

  • クラス、インターフェース名
  • self、オブジェクト自身

version5.0.0はクラス関係のものが型宣言できていた。

php 5.1.0から

  • array、配列

php 5.4.0から

  • callable、ざっくり言うと関数

php7.0.0から

  • bool true/falseのやつ
  • float
  • int
  • string
  • iterable、繰り返し関連(配列とかオブジェクトとか連想配列)

iterableとは、厳密には「array, traversable, instanceof」と公式では定義されている。上記の一覧を見てわかるように、基本的にはphp7.0.0以降を使っておけば、型変換については問題ないだろう。

参考記事:PHP: Traversable - Manual

戻り値の型宣言(タイプヒンティング)はできるのか?

結論から言うと、php7から戻り値の型宣言ができるようになった。戻り値で使える型は、引数と全く同じだ。

参考記事:PHP: 返り値 - Manual

戻り値の型宣言の方法は、引数の後にコロンを入力して、その後に型を宣言すると良い。例えば、以下の様に行う。

<?php
function mult_two(int $num): float {
return $num * 2;
}
var_dump(mult_two(2));  // float(4) と表示
?>

上記のコードでは、戻り値の型宣言をしなければint型の4が表示されるが、float型を宣言することで、戻り値が型変換されてfloat型の4として返されいるのが分かる。

上記のコードではint型からfloat型に型変換されるからエラーがでなかったが、型宣言をfloatからarrayに変えると、以下の様に「mult_two()の戻り値はintでなければダメだよ」と言うエラーが発生する。

PHP Fatal error:  Uncaught TypeError: Return value of mult_two() must be of the type array, integer returned in /home/hogehoge/sam.php:7

型宣言としてのnullとかvoidとか

php7.1からは型宣言としてnullvoidが使えるようになった。

参考:PHP: 新機能 - Manual

例えば、null型の場合は型宣言の先頭に?を付ければ良い。

function test(?string $name)
{
var_dump($name);
}

でも、正直nullの型宣言をいつ使うのは今の所分かっていない。

おそらく、voidの方が実用性は高いだろう。

function swap(): void
{
処理
}

voidを使えばC言語チックに戻り値がない事を明記できるので、個人的には使う頻度は高い。

おまけ:suinさんのツイート内のコードが上手く動かない件

本記事の冒頭にsuinさんのツイートを紹介した。

function print_count(int $count) {
echo "チョコを{$count}個もらいました";
}

という関数を

print_count('1個もチョコ、もらえませんでした');

で呼び出すと「チョコを1個もらいました」と出力してくれるPHPは優しかった。

— suin❄️PHPでオブジェクト指向 (@suin) February 14, 2019

個人的にはすごく面白いと思ったのだが、どうやらphp7.1以降は上記のツイート内のコードはエラーが発生してしまうようだ。

Warning: A non-numeric value encountered in 

参考記事:PHP: その他の変更 - Manual

なので、上記のコードを動かしたい場合は、phpのバージョンを7.0未満に下げる必要がある。