Contents
1️⃣ PHP 8.3 の主な変更点(公式リリースノート抜粋)
| カテゴリ | 新機能・改善点 | 影響範囲 |
|---|---|---|
| 型システム | Intersection Types (A&B) が正式実装。Enum に対して backed 型の明示が可能に。 |
静的解析や IDE 補完が向上し、より厳密な型定義が書けます。 |
| readonly | readonly クラス全体 (readonly class) が導入。clone 時はプロパティの値がコピーされ、未初期化状態になることはありません(ただし、未初期化 readonly プロパティへアクセスすると Error)。 |
不変オブジェクト設計がシンプルに。 |
| クラス定数 | public / protected / private の可視性が付与可能に。 |
継承階層でのカプセル化が強化されます。 |
| パフォーマンス | JIT と OPCache が微調整され、典型的な Web アプリで 4〜6 % 程度のスループット向上(公式ベンチマーク参照)。 | 高トラフィック環境での応答速度が若干改善。 |
| 非推奨化 | 動的プロパティ ($obj->newProp) が Deprecated に。代替は __get/__set もしくは明示的な型付きプロパティ。 |
コードベースの安全性と可読性が向上。 |
| その他 | fsync() / fdatasync() は PHP 8.3 では実装されていません。(※従来通り fflush() と OS の同期機構を組み合わせて使用)random_bytes() にオプションパラメータは未追加です。 |
誤情報の混入防止のため、ここに明示しておきます。 |
出典:PHP 公式マイグレーションガイド(https://www.php.net/manual/ja/migration83.php)および PHP Blog のリリースノート。
2️⃣ 安全な移行手順 – 静的解析と自動リファクタリング
2.1 phpstan と rector の基本設定
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 開発依存としてインストール composer require --dev phpstan/phpstan rector/rector # phpstan.neon(PHP 8.3 用)例 includes: - vendor/phpstan/phpstan/conf/bleedingEdge.neon parameters: level: max paths: - src/ phpVersion: 80300 # PHP 8.3 を明示 # rector のセットアップ(php83 プリセット) cat > rector.php <<'EOF' <?php return static function (\Rector\Config\RectorConfig $rectorConfig): void { $rectorConfig->sets([\Rector\Set\ValueObject\SetList::PHP_83]); }; EOF |
|
1 2 3 4 5 |
# 解析と自動修正の実行フロー vendor/bin/phpstan analyse # エラー・警告を一覧化 vendor/bin/rector process src --dry-run # 修正内容をプレビュー vendor/bin/rector process src # 本番適用(要コードレビュー推奨) |
2.2 移行時に注視すべきポイント
| 項目 | チェック内容 | 推奨アクション |
|---|---|---|
| readonly クラス・プロパティ | clone 後の値が期待通りか、未初期化 readonly へのアクセスはないか |
必要なら __clone() で再代入(コンストラクタ呼び出し) |
| クラス定数可視性 | public const が外部に漏れていないか、protected / private の使用が適切か |
アクセス権限を整理し、IDE の補完で確認 |
| 動的プロパティ | $obj->newProp が出現していないか |
__get/__set へ置き換えるか、型付きプロパティを追加 |
| Intersection Types | 関数シグネチャに A&B を導入できる箇所があるか |
型宣言を書き換えて静的解析で検証 |
3️⃣ クラス定数の可視性 – 実装例とベストプラクティス
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class BaseConfig { public const VERSION = '1.0'; // 公開 API protected const DEFAULT_TIMEOUT = 30; // 継承先で利用 private const SECRET_KEY = 'abc123'; // クラス内部限定 } class AppConfig extends BaseConfig { public function getTimeout(): int { return self::DEFAULT_TIMEOUT; } // 外部からはアクセス不可 → Fatal error が期待通りに発生 } |
活用シーン
| シナリオ | 定数の可視性選択 | 効果 |
|---|---|---|
| 公開 API のステータスコード | public |
外部ライブラリやクライアントが直接参照可能 |
| ライブラリ内部でのみ使用するフラグ | private |
カプセル化により誤用を防止 |
| 継承先でも共通設定したいデフォルト値 | protected |
子クラスから安全に再利用 |
4️⃣ readonly プロパティと clone の正しい挙動
4.1 挙動の概要(PHP 8.3)
- コピー:
cloneによってreadonlyプロパティは元オブジェクトと同じ値がそのままコピーされます。 - 再代入禁止:クローン後にプロパティへ再代入しようとすると
Error: Cannot modify readonly propertyがスローされます。 - 未初期化アクセス:コンストラクタで設定されていない
readonlyプロパティにアクセスした場合、Error: Uninitialized readonly propertyが発生します。
4.2 実装例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class User { public readonly string $id; public function __construct(string $id) { $this->id = $id; } } $u1 = new User('A01'); $u2 = clone $u1; // $u2->id は 'A01' と同じ値 // 再代入はエラーになる try { $u2->id = 'B02'; } catch (Error $e) { echo $e->getMessage(); // Cannot modify readonly property User::$id } |
4.3 移行チェックリスト
- 検索:
cloneが使用されているクラスをgrep -R "clone" src/等で抽出。 - 静的解析:phpstan のレベル
maxでreadonlyプロパティの未初期化アクセスを検出。 - テスト:クローン後に期待通りの値が保持されているか、または意図的に
__clone()で再設定するケースをユニットテストで確認。
|
1 2 3 4 5 6 7 8 9 10 |
class Config { public readonly string $name; public function __construct(string $name) { $this->name = $name; } // 必要なら clone 時に別名へ変更(例外的なケース) public function __clone(): void { $this->name .= '_copy'; } } |
5️⃣ 型システムの拡張 – Intersection Types と Enum の改善
5.1 Intersection Types (A&B)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
interface Loggable { public function log(string $msg): void; } interface JsonSerializable { public function jsonSerialize(): mixed; } class Logger implements Logable, JsonSerializable { // 実装省略 } /** * Loggable & JsonSerializable を同時に満たすオブジェクトだけを受け取る */ function process(Loggable&JsonSerializable $obj): void { $obj->log('start'); echo json_encode($obj); } |
- ポイント:
Loggable&JsonSerializableのように複数インターフェイスの同時実装を型で表現でき、ドキュメントと静的解析が一致します。
5.2 Enum のバックエンド型宣言
|
1 2 3 4 5 6 |
enum Status: string { case SUCCESS = 'success'; case FAILURE = 'failure'; // __toString が自動実装されるので文字列化が簡潔になる } |
- 利点:
Status::SUCCESS->valueで文字列取得、またはecho Status::FAILURE;と書くだけで同等の出力が得られます。
6️⃣ I/O・セキュリティ関連 – 実装上の注意点
| 項目 | 現状 (PHP 8.3) | 推奨代替手段 |
|---|---|---|
fsync() / fdatasync() |
未実装(公式関数は存在しない) | fflush($handle); に加えて OS の同期コマンド (sync) を必要に応じて呼び出すか、外部拡張 (PECL dio) を利用 |
random_bytes() オプション |
なし(第2引数は未定義) | 従来通り random_bytes($length) を使用し、失敗時は例外捕捉で代替 (openssl_random_pseudo_bytes) を実装 |
注意:上記機能は PHP コアに含まれていないため、誤情報が流布しやすいポイントです。利用する際は公式マニュアルを必ず確認してください。
7️⃣ 動的プロパティの非推奨化と安全な置き換え例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class UserProfile { public string $name; private array $meta = []; // 動的プロパティの代替 public function __get(string $key) { return $this->meta[$key] ?? null; } public function __set(string $key, $value): void { $this->meta[$key] = $value; } } |
- ベストプラクティス
- 可能な限り 型付きプロパティ を明示的に宣言。
- 動的データは内部配列 (
$meta) に集約し、__get/__setでアクセサーを提供することで IDE の補完と静的解析が有効になる。
8️⃣ まとめ & 次のアクション
- 公式情報に基づく認識
fsync()/fdatasync()、random_bytes()のオプションは未実装。誤解を防ぐためにドキュメントで明示。-
readonlyプロパティは clone 時も値がコピーされ、未初期化アクセス時にエラーが発生するだけです。 -
移行のフロー
- ローカル環境へ PHP 8.3 をインストール(
brew,apt,docker等)。 phpstan + rectorでコードベースを解析・自動修正。readonly、クラス定数可視性、動的プロパティの変更点を単体テストで検証。-
本番ステージング環境で負荷テスト(公式ベンチマークは参考値)し、性能差を確認。
-
開発チームへの共有
- 新しい Intersection Types と Enum のバックエンド型 を利用した設計ガイドラインを作成。
readonly classで不変オブジェクトを導入し、意図的なミュータビリティのみを許容するコードベースへ徐々にシフト。
次のステップ:まずはサンプルプロジェクトで
readonlyクラス・Intersection Types を試し、その挙動を CI に組み込んで自動検証を行いましょう。公式マイグレーションガイド(https://www.php.net/manual/ja/migration83.php)と併せて、全体像を把握することが成功への鍵です。
このドキュメントは、2026‑04‑16 時点で確認できた公式情報に基づき作成しています。今後の PHP バージョンアップや RFC の採択状況に応じて内容が変わる可能性がありますので、定期的な見直しを推奨します。