型宣言
関数のパラメータや戻り値、 クラスのプロパティ (PHP 7.4.0 以降)、クラス定数 (PHP 8.3.0 以降) に対して型を宣言することができます。 これによって、その値がコール時に特定の型であることを保証できます。 その型でない場合は、TypeError がスローされます。
PHP がサポートしている単一の型それぞれを、 ユーザーが行う型宣言の中で使うことができます。 但し、resource 型を除きます。 このページでは、それぞれの型がいつ利用可能になったかの変更履歴や、 型宣言におけるそれらの使い方について記しています。
注意:
クラスがインターフェイスのメソッドを実装したり、 親クラスで既に定義されているメソッドを再実装する場合、 そのメソッドは、既に存在するメソッドと互換性がなければなりません。 共変性と反変性 のルールに従っている場合、メソッドには互換性があります。
変更履歴
バージョン | 説明 |
---|---|
8.3.0 | クラス、インターフェイス、トレイト、そして列挙型の定数は、新たに型宣言をサポートするようになりました。 |
8.2.0 | DNF 型のサポートが追加されました。 |
8.2.0 | リテラル型 true のサポートが追加されました。 |
8.2.0 | null と false 型が、独立した型として使えるようになりました。 |
8.1.0 | 交差型のサポートが追加されました。 |
8.1.0 | 戻り値を void とした関数からリファレンスを返すことは、 推奨されなくなりました。 |
8.1.0 | 戻り値にのみ指定できる型として、 never 型のサポートが追加されました。 |
8.0.0 | mixed 型のサポートが追加されました。 |
8.0.0 | 戻り値にのみ指定できる型として、 static 型のサポートが追加されました。 |
8.0.0 | union 型のサポートが追加されました。 |
7.4.0 | クラスのプロパティに、型宣言のサポートが追加されました。 |
7.2.0 | object 型のサポートが追加されました。 |
7.1.0 | iterable 型のサポートが追加されました。 |
7.1.0 | void 型のサポートが追加されました。 |
7.1.0 | nullable な型のサポートが追加されました。 |
基本型を使うときの注意
基本型は、ここで説明する小さな注意事項はいくつかあるものの、 わかりやすい振る舞いをします。
スカラー型
スカラー型(bool, int,
float, string) のエイリアスはサポートされていません。
つまり、これらはクラスやインターフェイスの名前として扱われているということです。
たとえば、型の宣言に boolean
を使った場合、
値が boolean
クラスまたはインターフェイスのインスタンスであることが要求されます。
bool 型ではありません。
<?php
function test(boolean $param) {}
test(true);
?>
上の例の PHP 8 での出力は、このようになります。:
Warning: "boolean" will be interpreted as a class name. Did you mean "bool"? Write "\boolean" to suppress this warning in /in/9YrUX on line 2 Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean, bool given, called in - on line 3 and defined in -:2 Stack trace: #0 -(3): test(true) #1 {main} thrown in - on line 2
void
注意:
void を返す関数からリファレンスを返すことは、PHP 8.1.0 以降は推奨されなくなりました。 なぜなら、関数の定義そのものが矛盾しているからです。 PHP 8.1.0 より前のバージョンでは、 関数をコールした際に次のような
E_NOTICE
が発生していました: Only variable references should be returned by reference<?php
function &test(): void {}
?>
Callable
この型は、クラスのプロパティの型宣言では使うことができません。
注意: 関数のシグネチャに指定することもできません。
リファレンス渡しのパラメータに対する型宣言
リファレンス渡しのパラメータに対して宣言される型は、 関数の入り口で だけ チェックされます。 しかし、関数から返される時はチェックされません。 これは、変数のリファレンスについては、関数が型を変更できるということです。
例1 リファレンス渡しのパラメータに対する型宣言
<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>
上の例の出力は、 たとえば以下のようになります。
int(1) Fatal error: Uncaught TypeError: array_baz(): Argument #1 ($param) must be of type array, int given, called in - on line 9 and defined in -:2 Stack trace: #0 -(9): array_baz(1) #1 {main} thrown in - on line 2
複合型を使うときの注意
複合型を宣言する場合、制限がいくつか存在します。 また、簡単なバグを防ぐために、型の冗長チェックがコンパイル時に行われます。
PHP 8.2.0 より前のバージョン、 つまり DNF 型がサポートされる前は、 交差型とunion型を組み合わせることはできませんでした。
union 型
PHP 8.2.0 より前のバージョンでは、
false
と null 型は
独立した型として使えず、
union 型でそれらだけを指定することも許されませんでした。
つまり、false
, false|null
,
?false
のような型はいずれも許されませんでした。
nullable な型とシンタックスシュガー
単一の基本型を宣言した場合、
型の名前の前にクエスチョンマーク (?
) を付けることで、nullable であるという印を付けることができます。
よって、?T
と T|null
は同じ意味です。
注意: この文法は、PHP 7.1.0 以降でサポートされており、 一般化された union 型がサポートされる前から存在します。
注意:
デフォルト値に
null
を指定することで、 null を許容するパラメータを指定することができます。 これは、子クラスでデフォルト値が変更された場合にクラスの互換性が壊れ、 型宣言で null 型を追加しなければならなくなるため、おすすめできません。例2 引数にnullを許容する古いやり方
<?php
class C {}
function f(C $c = null) {
var_dump($c);
}
f(new C);
f(null);
?>上の例の出力は以下となります。
object(C)#1 (0) { } NULL
重複した冗長な型
複合型の宣言に関する単純なバグを見つけるため、 クラスの読み込みを行わずに検出できる冗長な型はコンパイル時にエラーになります。 たとえば、以下のような場合です:
-
名前が解決された型は、一度しか現れることができません。
int|string|INT
やCountable&Traversable&COUNTABLE
のような型はエラーになります。 - mixed 型を複合型で使うとエラーになります。
- union 型に適用される制限:
-
交差型に適用される制限:
- クラス型でない型を、交差型で使うとエラーになります。
- self, parent, static のいずれかを、交差型で使うとエラーになります。
-
DNF 型に適用される制限:
- より広い型をひとつ使った場合、 それより狭い型は冗長とみなされます。
- ふたつの等しい交差型を使った場合、冗長とみなされます。
注意: これによって、型が "最低限" であることは保証しません。 なぜなら、最低限であることを保証するためには、 使われている全てのクラスの型を読み込まなければならないからです。
たとえば、A
と B
がクラスのエイリアスだったとします。
この場合、A|B
は A
または B
のみに縮めることができますが、
正しい union 型です。 同様に、B extends A {}
というクラスがあった場合、 A|B
は A
のみに縮めることができますが、
正しい union 型です。
<?php
function foo(): int|INT {} // 許されません
function foo(): bool|false {} // 許されません
function foo(): int&Traversable {} // 許されません
function foo(): self&Traversable {} // 許されません
use A as B;
function foo(): A|B {} // 許されません ("use" は名前解決の一部です)
function foo(): A&B {} // 許されません ("use" は名前解決の一部です)
class_alias('X', 'Y');
function foo(): X|Y {} // 問題ありません (冗長かどうかは、実行時にだけわかります)
function foo(): X&Y {} // 問題ありません (冗長かどうかは、実行時にだけわかります)
?>