はじめに
PHPはもともと動的型付け言語であり、変数の型を意識せずに書けることが魅力でした。しかし規模が大きくなるにつれ、「引数に何を渡せばいいのかわからない」「関数が何を返すのか不明」といった問題が起きやすくなります。
PHP 7以降に強化された**型宣言(Type Declaration)**を使うことで、こうした問題を事前に防ぎ、コードの可読性と安全性を高めることができます。この記事では型宣言の基本から実践的な使い方まで、順を追って解説します。
スカラー型の宣言
PHP 7.0から、引数と戻り値にスカラー型(基本的な型)を指定できるようになりました。
<?php
function add(int $a, int $b): int
{
return $a + $b;
}
echo add(3, 5); // 8
echo add(3.7, 5); // 8(暗黙の型変換が行われる)
指定できる主なスカラー型は次のとおりです。
| 型 | 説明 |
|---|---|
int | 整数 |
float | 浮動小数点数 |
string | 文字列 |
bool | 真偽値 |
strict_typesで厳格モードに切り替える
デフォルトでは、PHPは型を自動的に変換(キャスト)します。たとえば int を期待する関数に "3" (文字列)を渡しても動作します。これを防ぐには、ファイルの先頭で declare(strict_types=1) を宣言します。
<?php
declare(strict_types=1);
function multiply(int $a, int $b): int
{
return $a * $b;
}
echo multiply(3, 4); // 12
echo multiply("3", 4); // TypeError が発生!
厳格モードを有効にすると、型が一致しない場合は TypeError がスローされます。チーム開発やライブラリ作成では、ファイルごとに strict_types=1 を付けることを強くおすすめします。
戻り値の型宣言
関数が何を返すかを明示するには、引数リストの後ろにコロン : で型を指定します。
<?php
declare(strict_types=1);
function greet(string $name): string
{
return "こんにちは、{$name}さん!";
}
echo greet("太郎"); // こんにちは、太郎さん!
戻り値がない場合は void を使います。
function logMessage(string $message): void
{
echo "[LOG] " . $message . PHP_EOL;
// return は書けない(return; だけはOK)
}
nullable型:nullを許容する
引数や戻り値に null を許容したい場合は、型名の前に ? を付けます。
<?php
declare(strict_types=1);
function findUser(int $id): ?string
{
$users = [1 => "Alice", 2 => "Bob"];
return $users[$id] ?? null; // 存在しなければnullを返す
}
var_dump(findUser(1)); // string(5) "Alice"
var_dump(findUser(9)); // NULL
これにより「値があればその型、なければ null」という実態に即した表現が可能になります。
Union型:複数の型を受け付ける(PHP 8.0以降)
PHP 8.0では Union型 が導入され、| で複数の型を指定できるようになりました。
<?php
declare(strict_types=1);
function formatInput(int|string $value): string
{
if (is_int($value)) {
return "整数: {$value}";
}
return "文字列: {$value}";
}
echo formatInput(42); // 整数: 42
echo formatInput("hello"); // 文字列: hello
null も Union型に含めることができます。?string は string|null と同等です。
function process(int|float|null $value): string
{
if ($value === null) return "値なし";
return (string)($value * 2);
}
クラスやインターフェースを型として使う
スカラー型だけでなく、クラスやインターフェースも型として指定できます。依存注入(DI)パターンでよく使われます。
<?php
declare(strict_types=1);
interface LoggerInterface
{
public function log(string $message): void;
}
class ConsoleLogger implements LoggerInterface
{
public function log(string $message): void
{
echo "[Console] " . $message . PHP_EOL;
}
}
class App
{
public function __construct(private LoggerInterface $logger) {}
public function run(): void
{
$this->logger->log("アプリを起動しました");
}
}
$app = new App(new ConsoleLogger());
$app->run(); // [Console] アプリを起動しました
インターフェースを型にすることで、具体的な実装に依存しない柔軟なコードが書けます。
まとめ
PHPの型宣言を整理すると、次のようになります。
| 機能 | 書き方 | 導入バージョン |
|---|---|---|
| スカラー型(引数) | function f(int $a) | PHP 7.0 |
| 戻り値型 | function f(): string | PHP 7.0 |
| nullable型 | function f(?string $a) | PHP 7.1 |
| void型 | function f(): void | PHP 7.1 |
| Union型 | function f(int|string $a) | PHP 8.0 |
| 厳格モード | declare(strict_types=1) | PHP 7.0 |
型宣言を積極的に活用することで、バグの早期発見・IDEによる補完の向上・コードの自己文書化が実現できます。最初は慣れが必要ですが、strict_types=1 と戻り値型の宣言から始めるだけでも大きな効果があります。ぜひ日常のPHP開発に取り入れてみてください。