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型 ?Type

void 戻り値

iterable
nullを許容する型宣言
戻り値なしの明示的宣言
配列またはTraversableを受け入れる
function test(?string $str): void
function 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|Type2

mixed

static

名前付き引数
複数の型を受け入れる
すべての型を受け入れる
遅延静的束縛の戻り値型
引数を名前で指定可能
function test(int|float $num): string|null
function test(mixed $value)
public static function create(): static
PHP 8.1
2021年11月
Intersection型 Type1&Type2

never

readonly プロパティ

new in initializers
複数の型を同時に満たす
決して戻らない関数
一度だけ設定可能なプロパティ
デフォルト値でnewが使用可能
function test(Countable&ArrayAccess $data)
function terminate(): never
public readonly string $id;
PHP 8.2
2022年12月
DNF型
(Disjunctive Normal Form)
(A&B)|C

true, false, null 型

readonly クラス
IntersectionとUnionの組み合わせ

リテラル型のサポート

すべてのプロパティがreadonly
function test((Stringable&Countable)|array $data)
function isValid(): true|false
readonly 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 {
    // より複雑な型の組み合わせが可能
}

型宣言の記法まとめ

記法バージョン意味
Type5.0+必須の型function test(string $s)
Type = null5.0+デフォルト値でnull許容function test(string $s = null)
?Type7.1+Nullable型function test(?string $s)
Type1|Type28.0+Union型(または)function test(int|string $v)
Type1&Type28.1+Intersection型(かつ)function test(A&B $v)
(A&B)|C8.2+DNF型(組み合わせ)function test((A&B)|C $v)

特殊な型

バージョン説明
self5.0+定義されたクラス自身を返す
parent5.0+親クラスを返す
array5.1+配列
callable5.4+呼び出し可能な型
void7.1+戻り値なし
iterable7.1+配列またはTraversable
object7.2+任意のオブジェクト
mixed8.0+すべての型を受け入れる
static8.0+呼び出されたクラス自身を返す
never8.1+決して戻らない(例外をthrowするか終了する)
true8.2+真偽値のtrue
false8.2+真偽値のfalse
null8.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では、非常に強力で柔軟な型システムが利用できます!