PHP8へのバージョンアップに伴い、これまで曖昧に許容されていた引数の型が厳格にチェックされるようになりました。
本記事では、よく遭遇する「Fatal error: Uncaught TypeError: Argument xxxx must be of type …」というエラーの原因や解決策について、いくつかの具体例とともに説明します。
これを読めば、PHP8特有の型エラーメッセージへの対処法や、コードリファクタリングのポイントを把握できるようになります。
PHP8で発生するTypeErrorとは何か
PHP8では型システムが強化され、引数や戻り値の型に合わない値が渡された場合、TypeError
が即座にスローされます。
これにより、従来は不正な型変換が起きていてもエラーにならなかった場面で、実行時に明示的なエラーが発生するようになったのです。
「Argument xxxx must be of type YYY」のようなエラーメッセージは、関数やメソッドに指定した型ヒントに反した引数が渡されていることを示しています。
例: 引数がint型を要求している関数にstringを渡すケース
次のような関数を考えます。
function multiplyByTwo(int $number): int {
return $number * 2;
}
PHP7以前でもstrict_types=1
を指定していない限り、"10"
のような文字列を渡しても自動的にintへキャストされ、動作してしまう場面がありました。
しかし、PHP8では以下のようなコードはTypeError
が発生します。
echo multiplyByTwo("10");
実行結果:
Fatal error: Uncaught TypeError: Argument #1 ($number) must be of type int, string given
このエラーから分かるように、渡された引数が指定の型と合わない場合には明確なエラーメッセージが出力されます。
PHP8でよくあるTypeErrorの発生パターン
プリミティブ型同士の不一致
関数やメソッドがint
やstring
といったプリミティブ型を受け取るとき、異なるプリミティブ型を渡すと直ちにTypeError
が起きます。
これは従来のPHPが内部的に暗黙的な型変換を行っていた挙動と大きく異なります。
オブジェクト型の不一致
指定されたクラスやインターフェースのインスタンスでないものが渡された場合もTypeError
が発生します。
例えば、以下のようなコードを想定します。
interface LoggerInterface {
public function log(string $message): void;
}
class FileLogger implements LoggerInterface {
public function log(string $message): void {
// ファイルへログを書き込む処理
}
}
function writeLog(LoggerInterface $logger, string $message) {
$logger->log($message);
}
// 本来はLoggerInterfaceを実装したインスタンスを渡すべき
writeLog(new stdClass(), "テストメッセージ");
このコードを実行すると、
Fatal error: Uncaught TypeError: Argument #1 ($logger) must be of type LoggerInterface, stdClass given
というエラーが発生します。
このように、インターフェースやクラス型を明示している場合に、その型を満たさない引数が渡されると厳密なエラーとして通知されます。
対策と解決方法
渡す引数の型を再確認する
最も基本的な対処法は、エラーメッセージに示される引数が要求する型を確認し、実際に渡している値の型が適切か再チェックすることです。
例えば、int
が必要なのにstring
を渡している場合は、予め(int)$value
とキャストする、または受け取り側のロジックを変更して正しい型を提供するようにします。
nullやオプション引数の扱い
PHP8では、型付き引数にnull
を渡す場合にも注意が必要です。null
を許可したい場合は、型宣言を?int
や?string
のようにnullable型にする必要があります。
nullable指定が無い場合にnull
を渡すとTypeError
が発生します。
型宣言の見直し
もしも引数が多様な型を受け付ける必要がある場合は、ユニオン型(int|string
のような宣言)を用いるか、別のメソッドに分離して明確な役割分担を行うことができます。
PHP8からはユニオン型が導入されているため、複数の型を引数として許容したい場合はこの機能を活用できます。
テストと型チェックツールの活用
PHPCSやPHPStan、Psalmなどの静的解析ツールを用いて型チェックを強化することも有効です。
コードを書く段階で不正な型渡しが無いか検知できるため、本番実行時にエラーが出る前に問題点を修正できます。
このようなツールをCI環境に組み込み、自動的に型の整合性を保証する流れを構築することがおすすめです。
まとめ
PHP8で導入された厳密な型チェックにより、これまで曖昧に処理されていた型不整合が明確なエラーとして表面化するようになりました。
この変更は、コードの品質向上やバグの早期発見につながる一方で、既存コードをPHP8へ移行する際にはTypeError
の対応が必要になります。
本記事で紹介した例や対処法(引数の型見直し、nullable対応、ユニオン型の活用、静的解析ツールの活用など)を参考に、エラーが発生した際には問題個所を素早く特定し、コードベースを堅牢なものへアップデートしていくことが可能です。
これらの手順を踏むことで、PHP8への移行や新規開発時にも、型に関連するエラーを円滑に解決できるようになります。