関数のパラメータや戻り値、 クラスのプロパティ (PHP 7.4.0 以降) に対して型を宣言することができます。 これによって、その値が特定の型であることを保証できます。 その型でない場合は、TypeError がスローされます。
注意:
親クラスのメソッドをオーバーライドする場合、 子クラスのメソッドは、 親クラスで宣言された戻り値の型のいずれかに一致させなければなりません。 親クラスが戻り値の型を宣言していない場合、 子クラスのメソッドもそうしなければなりません。
型 | 説明 | バージョン |
---|---|---|
クラス/インターフェイス の名前 | 値が、指定したクラスやインターフェイスのインスタンスでなければいけません。 | |
self | 値が、型宣言が行われているクラスと同じクラスのインスタンスでなければいけません。 クラスの内部でのみ使えます。 | |
parent | 値が、型宣言が行われたクラスの、親クラスのインスタンスでなければいけません。 クラスの内部でのみ使えます。 | |
array | 値が、配列でなければいけません。 | |
callable | 値が、callable でなければいけません。 クラスのプロパティの型では宣言できません。 | |
bool | 値が、bool 値でなければいけません。 | |
float | 値が、float でなければいけません。 | |
int | 値が、int でなければいけません。 | |
string | 値が、文字列でなければいけません。 | |
iterable | 値が、配列か、Traversable のインスタンスでなければなりません。 | PHP 7.1.0 以降 |
object | 値が、object でなければなりません。 | PHP 7.2.0 以降 |
mixed | 値は、あらゆる値であることができます。 | PHP 8.0.0 以降 |
上記のスカラー型のエイリアスはサポートされていません。
つまり、これらはクラスやインターフェイスの名前として扱われているということです。
たとえば、型の宣言に 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
mixed 型は、 以下の union 型 と同等です。 object|resource|array|string|int|float|bool|null この型は、PHP 8.0.0 以降で利用可能です。
例1 クラスによる型宣言の基本
<?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);
?>
上の例の PHP 8 での出力は、このようになります。:
C D Fatal error: Uncaught TypeError: f(): Argument #1 ($c) must be of type C, E given, called in /in/gLonb on line 14 and defined in /in/gLonb:8 Stack trace: #0 -(14): f(Object(E)) #1 {main} thrown in - on line 8
例2 インターフェイスによる型宣言の基本
<?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);
?>
上の例の PHP 8 での出力は、このようになります。:
C Fatal error: Uncaught TypeError: f(): Argument #1 ($i) must be of type I, 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
例3 基本的な戻り値の型宣言
<?php
function sum($a, $b): float {
return $a + $b;
}
// float が返される点に注意
var_dump(sum(1, 2));
?>
上の例の出力は以下となります。
float(3)
例4 オブジェクトを返す
<?php
class C {}
function getC(): C {
return new C;
}
var_dump(getC());
?>
上の例の出力は以下となります。
object(C)#1 (0) { }
PHP 7.1.0 以降では、型の名前の前にクエスチョンマーク
(?
) を付けることで、nullable であるという印を付けられるようになりました。
こうすることで、その値の型が指定されたものか、null
であることを指定できます。
例5 Null を許容する型宣言
<?php
class C {}
function f(?C $c) {
var_dump($c);
}
f(new C);
f(null);
?>
上の例の出力は以下となります。
object(C)#1 (0) { } NULL
例6 Null を許容する戻り値の型宣言
<?php
function get_item(): ?string {
if (isset($_GET['item'])) {
return $_GET['item'];
} else {
return null;
}
}
?>
注意:
デフォルト値に
null
を指定することで null を許容する引数を指定することができます。 これは、継承関係を破壊するので推奨できません。例7 引数にnullを許容する古いやり方
<?php
class C {}
function f(C $c = null) {
var_dump($c);
}
f(new C);
f(null);
?>上の例の出力は以下となります。
object(C)#1 (0) { } NULL
単一の型を組み合わせて、複合型にすることができます。 PHP では、以下のやり方で型を組み合わせることができます:
交差型 を union型 と組み合わせて使うことはできません。
型を union として宣言すると、ひとつではなく、
複数の異なる型を値として受け入れることができます。
union 型は、T1|T2|...
という文法を使って指定します。
union 型は、PHP 8.0.0 以降で利用可能です。
null
型も union 型の一部としてサポートされています。
null を受け入れる union を作るために、
T1|T2|null
のような指定をすることができます。
既にある ?T
記法は、
よくある T|null
の短縮記法と考えられます。
null
は、単独の、独立した型として使うことは出来ません。
false
リテラルの型が、union の一部としてサポートされています。
歴史的な理由で、多くの内部関数が失敗時に null
ではなく false
を返しているためです。
strpos() 関数は、このような関数の典型例です。
false
疑似型は、単独の、独立した型
(単独な null を許容する型としても)
として使うことは出来ません。
したがって、false
, false|null
,
?false
はいずれも許されません。
true
リテラルの型は存在 しません
型を 交差型 として宣言すると、
クラス/インターフェイス として宣言された型を
(単一ではなく)複数すべて満たす値を受け入れることができます。
交差型は、T1&T2&...
という文法を使って指定します。
交差型は、PHP 8.1.0 以降で利用可能です。
複合型の宣言に関する単純なバグを見つけるため、 クラスの読み込みを行わずに検出できる冗長な型はコンパイル時にエラーになります。 たとえば、以下のような場合です:
int|string|INT
や
Countable&Traversable&COUNTABLE
のような型はエラーになります。
注意: これによって、型が "最低限" であることは保証しません。 なぜなら、最低限であることを保証するためには、 使われている全てのクラスの型を読み込まなければならないからです。
たとえば、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 {} // 問題ありません (冗長かどうかは、実行時にだけわかります)
?>
void
は、関数が値を返さないことを示す戻り値の型です。
よって、この型は union 型の一部として指定することが出来ません。
PHP 7.1.0 以降で利用できます。
注意:
void を返す関数からリファレンスを返すことは、PHP 8.1.0 以降は推奨されなくなりました。 なぜなら、関数の定義そのものが矛盾しているからです。 PHP 8.1.0 より前のバージョンでは、 関数を呼び出した際に次のような
E_NOTICE
が発生していました:Only variable references should be returned by reference
<?php
function &test(): void {}
?>
never
は、
関数が戻ってこないことを示す戻り値の型です。
これは、関数の中で exit() がコールされるか、
例外がスローされるか、
無限ループに入るかのいずれかであることを意味します。
よって、この型は union 型の一部として指定することが出来ません。
PHP 8.1.0 以降で利用できます。
never は、 型理論の用語で言うと、ボトム型にあたります。 つまり、全ての他の型の部分型であり、 継承する際に他の戻り値の型で置き換えることができます。
値が、メソッドが呼び出されているクラスと同じインスタンスでなければなりません。 PHP 8.0.0 以降で利用できます。
デフォルトでは、PHP は誤った型の値を 可能であれば期待されたスカラー型の宣言に従うよう自動的に変換します(coercive モード)。 たとえば、関数に int が与えられたが、 引数に文字列が期待されていた場合、 文字列型の値を取得します。
ファイルごとに strict モードを有効にすることができます。 strict モードでは、型宣言に正確に対応する値のみを受け入れ、 そうでない場合、TypeError がスローされます。 このルールに関する唯一の例外は、int の値が float 型の宣言に渡せることだけです。
内部関数の中からの関数呼び出しは、
strict_types
宣言の影響を受けません。
strict モードを有効にするには、declare
文を
strict_types
宣言と一緒に使います。
注意:
厳密な型付けは、strict モードが有効になったファイルの 内部 から行われる関数呼び出しに適用されます。 そのファイルで宣言された関数への呼び出しに対して適用されるわけではありません。 厳密な型付けが有効になっていないファイルから、 厳密な型付けが有効になっているファイルで定義された関数を呼び出した場合は、 呼び出し側の好み(型の強制)が尊重され、値は型変換されます。
注意:
厳密な型付けは、スカラー型の宣言に対してのみ定義されます。
例8 引数の値に対する厳密な型付け
<?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));
?>
上の例の PHP 8 での出力は、このようになります。:
int(3) Fatal error: Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, 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
例9 引数の値に対する型の自動変換
<?php
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
// これらは、整数型に変換されます: 以下の出力を参照!
var_dump(sum(1.5, 2.5));
?>
上の例の出力は以下となります。
int(3) int(3)
例10 戻り値に対する厳密な型付け
<?php
declare(strict_types=1);
function sum($a, $b): int {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>
上の例の出力は以下となります。
int(3) Fatal error: Uncaught TypeError: sum(): Return value must be of type int, float returned in -:5 Stack trace: #0 -(9): sum(1, 2.5) #1 {main} thrown in - on line 5
strict_types
が有効になっていない場合、
スカラー型の宣言は、限られた暗黙の型変換が行われます。
値の正確な型が union の一部に指定されていない場合、
次の順に対象となる型が選択されます:
例外として、値が文字列で、int と float が union に含まれていた場合、
型は既存の "数値形式の文字列" を解釈するセマンティクスによって決まります。
たとえば、"42"
の場合、
int が選ばれますし、
"42.0"
の場合、float が選ばれます。
注意:
上のリストに入っていない型については、暗黙の型変換が行われる対象ではありません。 特に、暗黙のうちに
null
やfalse
に変換されることはありません。
例11 union の型のひとつに変換される例
<?php
// int|string
42 --> 42 // 正確に型が一致
"42" --> "42" // 正確に型が一致
new ObjectWithToString --> "Result of __toString()"
// オブジェクトは int と互換性がないので、文字列にフォールバック
42.0 --> 42 // float は int と互換性がある
42.1 --> 42 // float は int と互換性がある
1e100 --> "1.0E+100" // int には大きすぎる float なので、文字列にフォールバック
INF --> "INF" // int には大きすぎる float なので、文字列にフォールバック
true --> 1 // bool は int と互換性がある
[] --> TypeError // 配列はint, string と互換性はない。
// int|float|bool
"45" --> 45 // int の数値形式の文字列
"45.0" --> 45.0 // float の文字列
"45X" --> true // 数値形式の文字列ではない。boolにフォールバック
"" --> false // 数値形式の文字列ではない。boolにフォールバック
"X" --> true // 数値形式の文字列ではない。boolにフォールバック
[] --> TypeError // 配列はint, float, bool と互換性はない。
?>
例12 リファレンス渡しの引数に対する型宣言
リファレンス渡し の引数に対して宣言される型は、関数の入り口でチェックされますが、 関数から返される時はチェックされません。よって、関数から戻った後は、 引数の型が変わっているかもしれません。
<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>
上の例の PHP 8 での出力は、このようになります。:
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
例13 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();
}
?>
上の例の PHP 8 での出力は、このようになります。:
int(3) Error: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 10