PHPタイプヒント(型宣言)の歴史
篠原 隆司
アフィリエイト広告を利用しています
このページの内容が役に立ったら X (旧twitter) でフォローして頂けると励みになります
挨拶や報告は無しで大丈夫です
「型宣言(タイプヒント)って書かなくても動くし、面倒だな…」と思っていませんか?
実は、型宣言を省略することで、バグの温床を作り出している可能性があります。PHPは動的型付け言語として、型を明示しなくても動作しますが、それゆえに実行時エラーやデバッグの困難さに悩まされることが少なくありません。
型宣言を使うべき3つの理由:
- バグの早期発見 - 実行前に型の不一致を検出できる
- コードの自己文書化 - 関数のシグネチャを見るだけで期待される型が分かる
- IDEの補完精度向上 - PhpStormやVS Codeの入力補完が劇的に改善される
本記事では、PHP 5.0から最新のPHP 8.4まで、20年間の型システムの進化を網羅的に解説します。各バージョンでどのような型宣言が使えるようになったのか、実務でどう活用すべきかを、具体的なコード例とともにご紹介します。
当社は20年以上にわたりPHPシステム開発に携わり、大規模なエンタープライズシステムから中小規模のWebアプリケーションまで、幅広いプロジェクトで型宣言を活用してきました。その経験から得られた実践的なノウハウを、技術者の皆様に共有いたします。
「どのバージョンでどの型が使えるの?」「レガシーコードのリファクタリングで型宣言を追加したい」「最新のPHP 8.xの型システムを理解したい」といった疑問に、この記事が答えます。
PHPタイプヒント(型宣言)の歴史
バージョン別対応表
| バージョン | 追加された型宣言 | 例 |
|---|---|---|
| PHP 5.0 2004年7月 | クラス/インターフェース型 オブジェクトの型宣言が可能に | function test(MyClass $obj) |
| PHP 5.1 2005年11月 | array配列の型宣言 | function test(array $arr) |
| PHP 5.4 2012年3月 | callable呼び出し可能な型の宣言 | function test(callable $callback) |
| PHP 7.0 2015年12月 | スカラー型宣言 • int• float• string• bool戻り値の型宣言 スカラー型のサポート開始 厳密モード( declare(strict_types=1))の導入 | function test(int $num): string |
| PHP 7.1 2016年12月 | Nullable型 ?Typevoid 戻り値iterablenullを許容する型宣言 戻り値なしの明示的宣言 配列またはTraversableを受け入れる | function test(?string $str): voidfunction test(iterable $items) |
| PHP 7.2 2017年11月 | object任意のオブジェクト型 | function test(object $obj) |
| PHP 7.4 2019年11月 | プロパティの型宣言 共変戻り値・反変引数 クラスプロパティに型指定可能 継承時の型の柔軟性向上 | private string $name;public ?int $age = null; |
| PHP 8.0 2020年11月 | Union型 Type1|Type2mixedstatic名前付き引数 複数の型を受け入れる すべての型を受け入れる 遅延静的束縛の戻り値型 引数を名前で指定可能 | function test(int|float $num): string|nullfunction test(mixed $value)public static function create(): static |
| PHP 8.1 2021年11月 | Intersection型 Type1&Type2neverreadonly プロパティ new in initializers複数の型を同時に満たす 決して戻らない関数 一度だけ設定可能なプロパティ デフォルト値でnewが使用可能 | function test(Countable&ArrayAccess $data)function terminate(): neverpublic readonly string $id; |
| PHP 8.2 2022年12月 | DNF型 (Disjunctive Normal Form) (A&B)|Ctrue, false, null 型 readonly クラス IntersectionとUnionの組み合わせ リテラル型のサポート すべてのプロパティがreadonly | function test((Stringable&Countable)|array $data)function isValid(): true|falsereadonly class User { ... } |
| PHP 8.3 2023年11月 | 型付きクラス定数 動的クラス定数の取得 クラス定数に型宣言が可能に | class Foo { public const string BAR = 'baz';} |
| PHP 8.4 2024年11月 | プロパティフック 非対称可視性 ゲッター/セッターのような動作 読み書きで異なるアクセス制御 | public string $name { get => strtoupper($this->name);}public private(set) string $id; |
詳細説明
PHP 5.x 時代(2004-2015)
- オブジェクトと配列の型宣言のみ
- 戻り値の型宣言なし
- Nullable型は
= nullで対応
PHP 7.0(2015)- 大きな転換点
- スカラー型宣言:
int,float,string,boolが使えるように - 戻り値の型宣言: 関数が返す型を指定可能に
- 厳密モード:
declare(strict_types=1);で型の厳密チェック
PHP 7.1(2016)- Nullable型
// 新しい書き方
function test(?string $name): ?int
// 古い書き方
function test(string $name = null)
PHP 7.4(2019)- プロパティ型宣言
class User {
private string $name;
private ?int $age = null;
private array $tags = [];
}
PHP 8.0(2020)- Union型の登場
function process(int|float $number): string|null {
// int または float を受け取る
// string または null を返す
}
PHP 8.1(2021)- Intersection型
// 両方のインターフェースを実装している必要がある
function process(Countable&ArrayAccess $data): void {
// $data は Countable かつ ArrayAccess を実装
}
PHP 8.2(2022)- DNF型
// (A かつ B) または C
function process((Stringable&Countable)|array $data): void {
// より複雑な型の組み合わせが可能
}
型宣言の記法まとめ
| 記法 | バージョン | 意味 | 例 |
|---|---|---|---|
Type | 5.0+ | 必須の型 | function test(string $s) |
Type = null | 5.0+ | デフォルト値でnull許容 | function test(string $s = null) |
?Type | 7.1+ | Nullable型 | function test(?string $s) |
Type1|Type2 | 8.0+ | Union型(または) | function test(int|string $v) |
Type1&Type2 | 8.1+ | Intersection型(かつ) | function test(A&B $v) |
(A&B)|C | 8.2+ | DNF型(組み合わせ) | function test((A&B)|C $v) |
特殊な型
| 型 | バージョン | 説明 |
|---|---|---|
self | 5.0+ | 定義されたクラス自身を返す |
parent | 5.0+ | 親クラスを返す |
array | 5.1+ | 配列 |
callable | 5.4+ | 呼び出し可能な型 |
void | 7.1+ | 戻り値なし |
iterable | 7.1+ | 配列またはTraversable |
object | 7.2+ | 任意のオブジェクト |
mixed | 8.0+ | すべての型を受け入れる |
static | 8.0+ | 呼び出されたクラス自身を返す |
never | 8.1+ | 決して戻らない(例外をthrowするか終了する) |
true | 8.2+ | 真偽値のtrue |
false | 8.2+ | 真偽値のfalse |
null | 8.2+ | null値 |
strict_types モード
<?php
declare(strict_types=1);
// このファイルでは型チェックが厳密になる
function add(int $a, int $b): int {
return $a + $b;
}
add(1, 2); // OK
add("1", "2"); // TypeError(厳密モードでは文字列→int変換されない)
?>
declare(strict_types=1): 厳密な型チェックdeclare(strict_types=0): 型の自動変換を許可(デフォルト)- ファイル単位で設定(他のファイルには影響しない)
現在のベストプラクティス(PHP 8.2+)
<?php
declare(strict_types=1);
class User {
// プロパティに型宣言
public function __construct(
private readonly int $id,
private string $name,
private ?string $email = null,
) {}
// Union型の活用
public function setAge(int|string $age): void {
$this->age = is_string($age) ? (int)$age : $age;
}
// Nullable型
public function getEmail(): ?string {
return $this->email;
}
// 厳密な戻り値型
public function getId(): int {
return $this->id;
}
}
互換性に関する注意
- 後方互換性: 新しい型宣言を使うと、古いPHPバージョンでは動作しません
- ライブラリ開発: サポート対象の最小PHPバージョンに合わせた型宣言を使用
- 段階的移行: PHP 7.0+ なら基本的な型宣言、PHP 8.0+ ならUnion型が使える
まとめ
- PHP 5.x: オブジェクトと配列のみ
- PHP 7.0: スカラー型と戻り値型宣言の追加(大転換)
- PHP 7.1: Nullable型 (
?Type) の導入 - PHP 7.4: プロパティの型宣言
- PHP 8.0: Union型 (
Type1|Type2) の導入 - PHP 8.1: Intersection型 (
Type1&Type2) の導入 - PHP 8.2: DNF型、リテラル型の導入
- PHP 8.3-8.4: より高度な型システムの機能追加
現在のPHP 8.2では、非常に強力で柔軟な型システムが利用できます!