PHP 7.4.24 Released!

型宣言

関数のパラメータや戻り値、 クラスのプロパティ (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 型

mixed 型は、 以下の union 型 と同等です。 object|resource|array|string|int|float|bool|null この型は、PHP 8.0.0 以降で利用可能です。

例1 クラスによる型宣言の基本

<?php
class {}
class 
extends {}

// このクラスは C を継承していません
class {}

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 { public function f(); }
class 
implements { public function f() {} }

// このクラスは I を実装していません
class {}

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(12));
?>

上の例の出力は以下となります。

float(3)

例4 オブジェクトを返す

<?php
class {}

function 
getC(): {
    return new 
C;
}

var_dump(getC());
?>

上の例の出力は以下となります。

object(C)#1 (0) {
}

Null を許容する型宣言

PHP 7.1.0 以降では、型の名前の前にクエスチョンマーク (?) を付けることで、nullable であるという印を付けられるようになりました。 こうすることで、その値の型が指定されたものか、null であることを指定できます。

例5 Null を許容する型宣言

<?php
class {}

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;
    }
}
?>

注意:

PHP 7.1.0 より前のバージョンでは、 デフォルト値に null を指定することで null を許容する引数を指定することが出来ました。 これは、継承関係を破壊するので推奨できません。

例7 引数にnullを許容する古いやり方

<?php
class {}

function 
f(C $c null) {
    
var_dump($c);
}

f(new C);
f(null);
?>

上の例の出力は以下となります。

object(C)#1 (0) {
}
NULL

union 型

型を union として宣言すると、ひとつではなく、 複数の異なる型を値として受け入れることができます。 union 型は、T1|T2|... という文法を使って指定します。 union 型は、PHP 8.0.0 以降で利用可能です。

Nullを受け入れる union 型

null 型も union 型の一部としてサポートされています。 null を受け入れる union を作るために、 T1|T2|null のような指定をすることができます。 既にある ?T 記法は、 よくある T|null の短縮記法と考えられます。

警告

null は、単独の、独立した型として使うことは出来ません。

false 疑似型

false リテラルの型が、union の一部としてサポートされています。 歴史的な理由で、多くの内部関数が失敗時に null ではなく false を返しているためです。 strpos() 関数は、このような関数の典型例です。

警告

false 疑似型は、単独の、独立した型 (単独な null を許容する型としても) として使うことは出来ません。 したがって、false, false|null, ?false はいずれも許されません。

警告

true リテラルの型は存在 しません

重複した冗長な型

union 型の宣言に関する単純なバグを見つけるため、 クラスの読み込みを行わずに検出できる冗長な型はコンパイル時にエラーになります。 たとえば、以下のような場合です:

  • 名前が解決された型は、一度しか現れることができません。 int|string|INT のような型はエラーになります。
  • bool 型が使われている場合、false 疑似型は追加で使えません。
  • object 型が使われている場合、クラスの型は追加で使えません。
  • iterable 型が使われている場合、 arrayTraversable は追加で使えません。

注意: これによって、型が "最低限" であることは保証しません。 なぜなら、最低限であることを保証するためには、 使われている全てのクラスの型を読み込まなければならないからです。

たとえば、AB がクラスのエイリアスだったとします。 この場合、A|BA または B のみに縮めることができますが、 正しい union 型です。 同様に、B extends A {} というクラスがあった場合、 A|BA のみに縮めることができますが、 正しい union 型です。

<?php
function foo(): int|INT {} // 許されません
function foo(): bool|false {} // 許されません

use as B;
function 
foo(): A|{} // 許されません ("use" は名前解決の一部です)

class_alias('X''Y');
function 
foo(): X|{} // 問題ありません (冗長かどうかは、実行時にだけわかります)
?>

返り値でのみ有効な型

void

void は、関数が値を返さないことを示す戻り値の型です。 よって、この型は union 型の一部として指定することが出来ません。 PHP 7.1.0 以降で利用できます。

static

値が、メソッドが呼び出されているクラスと同じインスタンスでなければなりません。 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 $aint $b) {
    return 
$a $b;
}

var_dump(sum(12));
var_dump(sum(1.52.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 $aint $b) {
    return 
$a $b;
}

var_dump(sum(12));

// これらは、整数型に強制されます: 以下の出力を参照!
var_dump(sum(1.52.5));
?>

上の例の出力は以下となります。

int(3)
int(3)

例10 戻り値に対する厳密な型付け

<?php
declare(strict_types=1);

function 
sum($a$b): int {
    return 
$a $b;
}

var_dump(sum(12));
var_dump(sum(12.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

union 型と型の強制

strict_types が有効になっていない場合、 スカラー型の宣言は、限られた暗黙の型強制に従います。 値の正確な型が union の一部に指定されていない場合、 次の順に対象となる型が選択されます:

  1. int
  2. float
  3. string
  4. bool
正確な型が union の中に存在するか、 値が PHP の既存の型チェックのセマンティクスによって型を強制できる場合、 その型が選択されます。 そうでない場合、次の型を試そうとします。

警告

例外として、値が文字列で、int と float が union に含まれていた場合、 型は既存の "数値形式の文字列" を解釈するセマンティクスによって決まります。 たとえば、"42" の場合、 int が選ばれますし、 "42.0" の場合、float が選ばれます。

注意:

上のリストに入っていない型については、暗黙の型の強制が行われる対象ではありません。 特に、暗黙のうちに nullfalse に強制されることはありません。

例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 $aint $b) {
    return 
$a $b;
}

try {
    
var_dump(sum(12));
    
var_dump(sum(1.52.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
add a note add a note

User Contributed Notes 2 notes

up
7
anisgazig at example dot com
4 months ago
same data type and same value but first function declare as a argument type declaration and return int(7)
and second fucntion declare as a return type declaration but return int(8).

function argument_type_declaration(int $a, int $b){
    return $a+$b;
}

var_dump(argument_type_declaration(3.5,4.7));
//output:int(7)

function return_type_declaration($a,$b) :int{
    return $a+$b;
}

var_dump(return_type_declaration(3.5,4.7));

//output:int(8)
up
4
toinenkayt (ta at ta) [iwonderr] gmail d
2 months ago
While waiting for native support for typed arrays, here are a couple of alternative ways to ensure strong typing of arrays by abusing variadic functions. The performance of these methods is a mystery to the writer and so the responsibility of benchmarking them falls unto the reader.

PHP 5.6 added the splat operator (...) which is used to unpack arrays to be used as function arguments. PHP 7.0 added scalar type hints. Latter versions of PHP have further improved the type system. With these additions and improvements, it is possible to have a decent support for typed arrays.

<?php
declare (strict_types=1);

function
typeArrayNullInt(?int ...$arg): void {
}

function
doSomething(array $ints): void {
    (function (?
int ...$arg) {})(...$ints);
   
// Alternatively,
   
(fn (?int ...$arg) => $arg)(...$ints);
   
// Or to avoid cluttering memory with too many closures
   
typeArrayNullInt(...$ints);

   
/* ... */
}

function
doSomethingElse(?int ...$ints): void {
   
/* ... */
}

$ints = [1,2,3,4,null];
doSomething ($ints);
doSomethingElse (...$ints);
?>

Both methods work with all type declarations. The key idea here is to have the functions throw a runtime error if they encounter a typing violation. The typing method used in doSomethingElse is cleaner of the two but it disallows having any other parameters after the variadic parameter. It also requires the call site to be aware of this typing implementation and unpack the array. The method used in doSomething is messier but it does not require the call site to be aware of the typing method as the unpacking is performed within the function. It is also less ambiguous as the doSomethingElse would also accept n individual parameters where as doSomething only accepts an array. doSomething's method is also easier to strip away if native typed array support is ever added to PHP. Both of these methods only work for input parameters. An array return value type check would need to take place at the call site.

If strict_types is not enabled, it may be desirable to return the coerced scalar values from the type check function (e.g. floats and strings become integers) to ensure proper typing.
To Top