目次
PHPを型安全にする
動的型付けスクリプト言語である、PHPにおけるタイプヒンティング(型宣言)と実行時に厳密にデータ型をチェックするstrictモードについてメモ。
環境 : PHP 7.4.2
タイプヒンティング(型宣言)とは
タイプヒンティングを用いることで引数と戻り値の型を明示し、指定することができる。
PHPStanなどの静的解析ツールと組み合わせることで実行前に記述ミスや不具合の原因となる箇所を発見しやすくなり、より安全なコーディングを実現できる。
タイプヒンティングで指定できる型はPHP5まではクラス名,self,array,callableだけだったが、PHP7からスカラ型とよばれる、bool,float,int,stringを型指定できるようになっている。
引数の型指定を行う
関数、メソッドの引数指定にタイプヒンティングを用いる。
例として下記、addメソッドの引数a,bの型として、int型を指定する。
(デフォルト引数に0を指定し、引数が渡ってこなかった場合に初期値として設定する)
<?php
namespace app\src;
class Calculator
{
public function add(int $a = 0, int $b = 0)
{
return $a + $b;
}
}
タイプヒンティングによる型の明示はそれ自体に型指定の強制力はなく、
もし指定した型でない値が渡された場合、エラーとはならず指定されていた型に自動的にキャスト(型変換)されて実行される。
(実行ファイル)
<?php
require_once __DIR__ . '/app/vendor/autoload.php';
$calculator = new app\src\Calculator();
$calculator->add(3, 3);
$calculator->add("3", "3");
2つ目のaddメソッド呼び出し時の文字列型の引数は数値に変換されて実行される。
厳密な型チェックを行う
指定した型以外の値が引数に渡された場合に例外を発生させるには、strictモードを有効にする。
メソッド呼び出し側で、
declare(strict_types=1)
を宣言することで引数に対して厳密な型チェックを有効にすることができる。
<?php
declare(strict_types=1);
require_once __DIR__ . '/app/vendor/autoload.php';
$calculator = new app\src\Calculator();
$calculator->add(3, 3);
$calculator->add("3", "3");
厳密な型チェックにより、TypeError例外を発生させることができる。
PHP Fatal error: Uncaught TypeError: Argument 1 passed to app\src\Calculator::add() must be of the type int, string given,
「int型が指定されているはずなのに、string型が渡されているよ」
declare(strict_types=1)の有効範囲
呼び出し側で行う、declare(strict_types=1)の宣言は間接的に実行されるメソッドに対しては効力がないようである。
例として下記のようにaddメソッドからサブルーチンとして定義されたプライベートなメソッドを実行する場合、引数のタイプヒンティングでstringが指定されているが、intの引数を渡してTypeError例外を発生することなく処理を実行できる。
<?php
namespace app\src;
class Calculator
{
public function add(int $a = 0, int $b = 0)
{
$this->stdOut($a + $b);
}
private function stdOut(string $result)
{
echo $result . "\n";
}
}
間接呼び出しに対しても厳密な型チェックが行われるようにするためには、下記のように定義側にもdeclare(strict_types=1)を宣言する必要がある。
<?php
declare(strict_types=1);
namespace app\src;
class Calculator
{
(略)
戻り値の型指定を行う
PHP7からの機能により、戻り値の型もタイプヒンティングできるようになっている。
関数、メソッドの宣言で括弧の後ろにコロンと指定する型の種類を記述することで戻り値の型を指定できる。
例として、addメソッドの戻り値の型としてstring型を指定する。
また、戻り値の型指定で厳密な型チェックを行う場合は呼び出し側ではなく定義側の先頭(この場合はクラス内)でstrict_typesを有効にする必要がある。
<?php
declare(strict_types=1);
namespace app\src;
class Calculator
{
public function add(int $a = 0, int $b = 0): string
{
return $a + $b;
}
}
戻り値の型が指定したものと一致しないため、TypeError例外を発生させることができる。
PHP Fatal error: Uncaught TypeError: Return value of app\src\Calculator::add() must be of the type string, int returned in
「戻り値の型はstring型でないといけないが、int型で返されているよ」