タイプヒンティング(Type Hinting)
パラメータ(引数)の型を指定できます。
指定した型のことをタイプヒント(型ヒント)といい、タイプヒントに一致しない型のパラメータ(引数)を受け付けません。(型が違うとエラー。)
PHP5から導入されました。 PHPでは型は内部的に柔軟に処理されるため、PHP5以前には型指定がありませんでした。
⇩ タイプヒンティングについて詳しくは下記サイトへ
型宣言
型宣言を使うと、関数の呼び出し時にパラメータが特定の型であることを要求できるようになります。 指定した値が不正な型であった場合はエラーとなります。
PHP 5 では、このエラーは recoverable fatal error でした。
PHP 7 では、この場合に TypeError 例外をスローします。
型宣言を指定するには、型の名前をパラメータ名の前に追加します。
パラメータのデフォルト値が NULL
である場合は、型宣言でも NULL
値を受け付けることができます。
有効な型
型 | 説明 | 利用可能な PHP の最低バージョン |
---|---|---|
クラス名 / インターフェイス名 | パラメータは、指定したクラスやインターフェイスのインスタンスでなければいけません。 | PHP 5.0.0 |
self | パラメータは、そのメソッドが定義されているクラスと同じクラスのインスタンスでなければいけません。 これが使えるのは、クラスメソッドやインスタンスメソッドだけです。 | PHP 5.0.0 |
array | パラメータは配列でなければいけません。 | PHP 5.1.0 |
callable | パラメータは callable でなければいけません。 | PHP 5.4.0 |
bool | パラメータは boolean 値でなければいけません。 | PHP 7.0.0 |
float | パラメータは float でなければいけません。 | PHP 7.0.0 |
int | パラメータは integer でなければいけません。 | PHP 7.0.0 |
string | パラメータは string でなければいけません。 | PHP 7.0.0 |
例7 クラスの型宣言の基本例
<?php
class C {}
class D extends C {}
// これは C を継承していません。
class E {}
function f(C $c) {
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
?>
上の例の出力は以下となります。
C D Fatal error: Uncaught TypeError: Argument 1 passed to f() must be an instance of C, instance of E given, called in - on line 14 and defined in -:8 Stack trace: #0 -(14): f(Object(E)) #1 {main} thrown in - on line 8
⇩ インターフェイスについては下記サイトへ
・PHPのinterfaceとは何か: Architect Note
例8 インターフェイスの型宣言の基本例
<?php
interface I { public function f(); }
class C implements I { public function f() {} }
// これは I を実装していません。
class E {}
function f(I $i) {
echo get_class($i)."\n";
}
f(new C);
f(new E);
?>
上の例の出力は以下となります。
C Fatal error: Uncaught TypeError: Argument 1 passed to f() must implement interface I, instance of E given, called in - on line 13 and defined in -:8 Stack trace: #0 -(13): f(Object(E)) #1 {main} thrown in - on line 8
例9 Null を許可する型宣言
<?php
class C {}
function f(C $c = null) {
var_dump($c);
}
f(new C);
f(null);
?>
上の例の出力は以下となります。
object(C)#1 (0) { } NULL
強い型付け
デフォルトでは、間違った型を渡された場合でも、可能な限りは来されている型に変換します。
たとえば、string を想定している関数のパラメータに integer が渡された場合は、その値を string 型として受け取ります。
ファイル単位で厳密な型チェックを有効にすることもできます。
この場合は、宣言されたとおりの型でない限りは受け付けず、 TypeError をスローします。
ただし、float が指定されているところに integer を渡した場合だけは例外です。
厳密な型チェックを有効にするには、declare 文を用いて strict_types を宣言します。
例10 厳密な型チェック
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
上の例の出力は以下となります。
int(3) Fatal error: Uncaught TypeError: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 9 and defined in -:4 Stack trace: #0 -(9): sum(1.5, 2.5) #1 {main} thrown in - on line 4
例11 弱い型チェック
<?php
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
// これらは integer 型として扱われます。出力例に注目!
var_dump(sum(1.5, 2.5));
?>
上の例の出力は以下となります。
int(3) int(3)
例12 TypeError の捕捉
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
try {
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
} catch (TypeError $e) {
echo 'Error: '.$e->getMessage();
}
?>
上の例の出力は以下となります。
int(3) Error: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 10
可長変引数
引数の個数を変えることが出来るとき(即ち、可変であるとき)可変長引数と呼びます。
⇩ 可長変引数については下記サイトへ
・PHPスクリプト講座:可変長の引数 | そふぃのphp入門
可変長引数リスト
PHP は、可変長引数をユーザー定義関数でサポートしています。 PHP 5.6 以降では ... を使って実装されており、 PHP 5.5 以前ではfunc_num_args( ), func_get_arg( ), func_get_args( ) 関数を使用します。
PHP 5.6 以降における ...
PHP 5.6 以降では、引数リストに ... トークンを含めることで、 その関数が可変長の引数を受け取ることを示せます。 引数は、指定した変数に配列として渡されます。次の例を参照ください。
例13 ... を使った、可変長引数へのアクセス
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
上の例の出力は以下となります。
10
関数を呼び出すときに ... を使うと、 配列変数や Traversable クラスを引数リストに含めることができます。
例14 引数での ... の使用例
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
上の例の出力は以下となります。
3 3
通常の引数を、... の前に指定することもできます。 この場合は、通常の引数リストにマッチしなかったのこりの引数が ... による配列に追加されます。
... トークンの前に、 タイプヒント を付加することもできます。 タイプヒントがある場合、... が取り込むすべての引数はそのヒントに従わなければいけません。
例15 タイプヒントつきの可変長引数
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// これは失敗します。null は DateInterval オブジェクトではないからです。
echo total_intervals('d', null);
?>
上の例の出力は以下となります。
3 days Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
可変長引数の 参照渡し もできます。その場合は、... の前にアンパサンド (&) を付加します。
古いバージョンの PHP
可変長引数に関して特別な構文は必要としません。しかし、関数の引数にアクセスするには func_num_args( )、func_get_arg( ) およびfunc_get_args( ) といった関数を使う必要があります。
先ほどの最初の例を、PHP 5.5 以前のバージョンで実装すると、以下のようになります。
例16 可変長引数へのアクセス (PHP 5.5 以前)
<?php
function sum() {
$acc = 0;
foreach (func_get_args() as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
上の例の出力は以下となります。
10
タイプヒンティングで指定可能な型は
- クラス名
- インタフェース名
- 配列 (PHP 5.1以降)
- callable (PHP 5.4以降)
- タイプヒントが付いたパラメータにはNULLを渡すことはできないが、パラメータのデフォルト値として「= null」と指定しておけばnullを渡すことも可能
だったのですが、
PHP7において、
- bool (パラメータはboolean)
- float (パラメータはfloat)
- int (パラメータはinteger)
- string (パラメータはstring)
スカラー型の型宣言が出来るようになったようです。
⇩ 詳しくは下記サイトへ
・【導入決定!】PHP7で実装されるスカラー型宣言とは? | 東北ギーク
タイプヒンティングを使うメリットとしては、
- クラス設計者は、インターフェイスの仕様に基づいてクラスのメソッドが作成できます。
- クラス使用者は、パラメータ(引数)に何を渡せばいいかが分かりやすくなります。
- つまり、クラス設計者の意図がクラス使用者に伝わりやすいという事らしいです。
⇩ 詳しくは下記サイトへ
PHPのオブジェクト指向入門 | オブジェクト指向PHP.NET
2017年10月21日(土) 追記
『独習PHP 第三版(著:山田祥寛)』 を読んで、PHP5系でタイプヒンティングと呼ばれていたものが、PHP7系では型宣言と呼ばれるようです。
PHP5系のタイプヒンティング
- 戻り値では型宣言は利用できない
- 引数で型を宣言できるのは配列/オブジェクトだけ(int/floatのような型はしてできない)
いろいろ制限のあったPHP5系のタイプヒンティングですが、PHP7系になって型宣言となってから、制限が緩和されたみたいです。
PHP7系の型宣言
※ただし、doubleやbooleanといった型は利用できないようです。
厳密な型チェックを有効にするには、ファイルの先頭に
<?php declare(strict_types=1);
と記述することで可能みたいです。
※厳密な型チェックは、PHP 7からでないと利用できないので注意です。
⇩ 詳しくは、下記書籍を参考で。