※当サイトの記事には、広告・プロモーションが含まれます。

PHP5.4から実装された『タイプヒンティング(型宣言)』とは? PHP7系では型宣言と呼ばれる

タイプヒンティング(Type Hinting)

パラメータ(引数)の型を指定できます。

指定した型のことをタイプヒント(型ヒント)といい、タイプヒントに一致しない型のパラメータ(引数)を受け付けません。(型が違うとエラー。)

PHP5から導入されました。 PHPでは型は内部的に柔軟に処理されるため、PHP5以前には型指定がありませんでした。

 

⇩  タイプヒンティングについて詳しくは下記サイトへ

【PHP】タイプヒンティング - Qiita

 

PHPマニュアル: 関数の引数 - Manualによると、

型宣言

注意:

型宣言は、PHP 5 ではタイプヒンティングとも呼ばれていました。

型宣言を使うと、関数の呼び出し時にパラメータが特定の型であることを要求できるようになります。 指定した値が不正な型であった場合はエラーとなります。
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 {}
class 
extends {}

// これは C を継承していません。
class {}

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 { 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);
?>

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

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 {}

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 を宣言します。

警告

厳密な型チェックを有効にすると、 戻り値の型宣言 にも影響を及ぼします。

注意:

厳密な型チェックが適用されるのは、それを有効にしたファイル の中からの関数呼び出しだけです。 そのファイル内で宣言されている関数に適用されるわけではありません。 厳密な型チェックを有効にしていないファイルから、 厳密な型チェックを有効にしたファイル内で定義された関数を呼び出した場合は、 呼び出し元の設定 (弱い型チェック) が適用されて、自動的に型変換を行います。

注意:

厳密な型チェックはスカラー型宣言に対してのみ定義されるものであり、 PHP 7.0.0 以降でなければ使えません。そもそもスカラー型宣言が追加されたのが PHP 7.0.0 だからです。

例10 厳密な型チェック

<?php
declare(strict_types=1);

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

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

var_dump(sum(12));

// これらは integer 型として扱われます。出力例に注目!
var_dump(sum(1.52.5));
?>

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

int(3)
int(3)

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

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

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

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

10

関数を呼び出すときに ... を使うと、 配列変数や Traversable クラスを引数リストに含めることができます。

例14 引数での ... の使用例

<?php
function add($a$b) {
    return 
$a $b;
}

echo 
add(...[12])."\n";

$a = [12];
echo 
add(...$a);
?>

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

3
3

通常の引数を、... の前に指定することもできます。 この場合は、通常の引数リストにマッチしなかったのこりの引数が ... による配列に追加されます。

... トークンの前に、 タイプヒント を付加することもできます。 タイプヒントがある場合、... が取り込むすべての引数はそのヒントに従わなければいけません。

例15 タイプヒントつきの可変長引数

<?php
function total_intervals($unitDateInterval ...$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(1234);
?>

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

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系の型宣言

f:id:ts0818:20171021095949p:plain

※ただし、doubleやbooleanといった型は利用できないようです。

厳密な型チェックを有効にするには、ファイルの先頭に

<?php
declare(strict_types=1);

と記述することで可能みたいです。

※厳密な型チェックは、PHP 7からでないと利用できないので注意です。

⇩  詳しくは、下記書籍を参考で。

独習PHP 第3版(山田祥寛) | 翔泳社の本

f:id:ts0818:20171021101100j:plain