株式会社WR

株式会社WR

WEB TOTAL CONSULTING

PHP 8.2の新機能——readonlyプロパティとEnum型の活用
ブログ一覧へ
技術ブログ

PHP 8.2の新機能——readonlyプロパティとEnum型の活用

PHP 8.2のreadonly class・Enum・Fibers・DNFタイプなど、弊社の開発で実際に活用している新機能を紹介します。

PHP 8.2の主な新機能

PHP 8.2は2022年12月にリリースされ、型システムの強化と読みやすいコードのための機能が中心です。弊社ではPHP 8.2を本番環境の標準バージョンとして採用しており、本記事ではよく使う機能を実践的に解説します。


readonlyプロパティ(8.1から拡張)

PHP 8.1でreadonly プロパティが導入され、8.2ではreadonly クラス全体に適用できるようになりました。

// PHP 8.2:クラス全体をreadonlyに
readonly class Money
{
    public function __construct(
        public readonly int    $amount,
        public readonly string $currency,
    ) {}

    // readonlyクラス内のメソッドはOK
    public function add(Money $other): static
    {
        if ($this->currency !== $other->currency) {
            throw new \InvalidArgumentException('通貨が異なります');
        }
        return new static($this->amount + $other->amount, $this->currency);
    }

    public function format(): string
    {
        return match($this->currency) {
            'JPY' => "¥{$this->amount}",
            'USD' => "\${$this->amount}",
            default => "{$this->amount} {$this->currency}",
        };
    }
}

// 使い方
$price    = new Money(5000, 'JPY');
$tax      = new Money(500, 'JPY');
$total    = $price->add($tax);

echo $total->format(); // ¥5500

// 変更しようとするとエラー
$price->amount = 9999; // Error: Cannot modify readonly property

Enum型(PHP 8.1から)——実践的な使い方

Enumは定数の集合を型安全に表現できます。弊社では注文ステータス・ユーザーロール・支払い方法などに積極活用しています。

// Backed Enum(値あり)
enum OrderStatus: string
{
    case Pending   = 'pending';
    case Confirmed = 'confirmed';
    case Shipped   = 'shipped';
    case Delivered = 'delivered';
    case Cancelled = 'cancelled';

    // ラベル(日本語表示用)
    public function label(): string
    {
        return match($this) {
            self::Pending   => '保留中',
            self::Confirmed => '確定',
            self::Shipped   => '発送済',
            self::Delivered => '配達完了',
            self::Cancelled => 'キャンセル',
        };
    }

    // 次に遷移可能なステータス
    public function allowedTransitions(): array
    {
        return match($this) {
            self::Pending   => [self::Confirmed, self::Cancelled],
            self::Confirmed => [self::Shipped, self::Cancelled],
            self::Shipped   => [self::Delivered],
            default         => [],
        };
    }

    public function canTransitionTo(self $next): bool
    {
        return in_array($next, $this->allowedTransitions());
    }
}
// Enumをモデルに適用
class Order extends Model
{
    protected $casts = [
        'status' => OrderStatus::class,
    ];

    public function confirm(): void
    {
        if (!$this->status->canTransitionTo(OrderStatus::Confirmed)) {
            throw new \LogicException(
                "ステータス「{$this->status->label()}」から確定に遷移できません"
            );
        }
        $this->update(['status' => OrderStatus::Confirmed]);
    }
}

// 使い方
$order = Order::find(1);
echo $order->status->label(); // "保留中"
$order->confirm();             // OK
$order->confirm();             // LogicException: ステータス「確定」から確定に遷移できません

Enumのバリデーション

// LaravelのFormRequestでEnum値のバリデーション
use Illuminate\Validation\Rule;

public function rules(): array
{
    return [
        'status' => ['required', Rule::enum(OrderStatus::class)],
    ];
}

// Enumから値一覧を取得
$validValues = array_column(OrderStatus::cases(), 'value');
// ['pending', 'confirmed', 'shipped', 'delivered', 'cancelled']

DNF型(Disjunctive Normal Form)

PHP 8.2でIntersection型とUnion型を組み合わせたDNF型が使えるようになりました。

// (AかつB) または (CかつD) という複合型
function processInput(
    (Countable&Iterator)|null $input
): void {
    if ($input === null) {
        return;
    }
    // $input は Countable かつ Iterator が保証される
    echo count($input);
    foreach ($input as $item) {
        // ...
    }
}

fibers(PHP 8.1から)——非同期処理の基礎

Fibersはコルーチンの仕組みで、処理を中断・再開できます。

$fiber = new Fiber(function(): void {
    $value = Fiber::suspend('最初の値');
    echo "再開時に受け取った値: {$value}\n";
    Fiber::suspend('2番目の値');
});

$val1 = $fiber->start();
echo "中断: {$val1}\n"; // "中断: 最初の値"

$val2 = $fiber->resume('こんにちは');
echo "再中断: {$val2}\n";
// "再開時に受け取った値: こんにちは"
// "再中断: 2番目の値"

非推奨機能——PHP 8.2で削除

機能 移行先
${var} 文字列補間 {$var}
動的プロパティ 明示的にプロパティを宣言する
utf8_encode() / utf8_decode() mb_convert_encoding()
FILTER_SANITIZE_STRING htmlspecialchars() など
// NG:PHP 8.2で非推奨の動的プロパティ
class User
{
    // $nameプロパティが未定義のまま使用
}
$user = new User();
$user->name = '山田'; // Deprecated警告

// OK:プロパティを宣言する
class User
{
    public string $name = '';
}

まとめ

PHP 8.2のreadonlyクラスとEnum型は、コードの不変性と型安全性を高め、バグを未然に防ぐ強力な機能です。弊社ではLaravelプロジェクトでこれらを積極的に活用し、保守性の高いシステムを構築しています。

PHP/Laravelによるシステム開発のご相談はお気軽にどうぞ。

Category 技術ブログ

Related Posts

関連記事

開発・技術のご相談はお気軽に

お見積りは無料です。まずはお気軽にご相談ください。

お問い合わせ →