PHP 8.2 の「Deprecated: Creation of dynamic property」警告を修正する方法

intermediate🐘 PHP2026-05-30| PHP 8.2+, Linux (Ubuntu/Debian), macOS, Windows, Docker (php:8.2-fpm)

Error Message

Deprecated: Creation of dynamic property ClassName::$property is deprecated
#php#php82#deprecated#dynamic-property#upgrade

深夜 2 時の本番環境での警告サーバーを PHP 8.2 にアップグレードした直後、エラーログが爆発的に増え始めていることに気づくかもしれません。アプリケーション自体は技術的には動作していますが、これらの非推奨(deprecation)警告は、本来気づくべき重要な問題を埋もれさせてしまいます。数千ものリクエストを処理している場合、これらのログは一晩で数ギガバイトにも達することがあります。PHP 8.2 では、サイレントなバグを検出し、エンジンのパフォーマンスを最適化するために、動的プロパティ(dynamic properties)の「やりたい放題」だった時代に正式に終止符を打ちました。

エラーメッセージdisplay_errors が有効な場合、ログや画面上で以下の特定の警告を確認してください。

Deprecated: Creation of dynamic property User::$email is deprecated in /var/www/html/src/Models/User.php on line 42

なぜこのエラーが発生するのかPHP 8.2 より前は、存在しないプロパティに値を代入しても、エンジンから何の警告も出ませんでした。これは便利ではありましたが、危険でもありました。例えば $this->emial = $val; のような単純なタイポ(入力ミス)があっても、エラーはスローされず、ただ無意味な新しいプロパティが作成されるだけでした。PHP は現在、この動作にフラグを立てています。PHP 9.0 では、この「利便性」はサイトをクラッシュさせる致命的なエラー(Fatal Error)になる予定です。

修正方法### 1. プロパティを明示的に宣言する(推奨される標準的な方法)これが最も堅牢な解決策です。プロパティを宣言することでコードの可読性が高まり、IDE のオートコンプリートが有効になり、静的解析ツールが本番環境にデプロイする前にエラーを検出できるようになります。

問題のあるコード:

class User {
    public function __construct($data) {
        $this->email = $data['email']; // 宣言されていない場合、警告が発生します
    }
}

修正後のコード:

class User {
    public string $email; // 型を指定して明示的に宣言

    public function __construct($data) {
        $this->email = $data['email'];
    }
}

2. #[AllowDynamicProperties] 属性を使用する(レガシーコード向けのショートカット)大規模なレガシーコードベースやデータ転送オブジェクト(DTO)を扱っている場合、すべてのプロパティを宣言するには数週間かかるかもしれません。その場合は、この属性を使用して、特定のクラスが「動的」であることを許可することをエンジンに伝えます。

use AllowDynamicProperties;

#[AllowDynamicProperties]
class LegacyModel {
    public function setDynamic($name, $value) {
        $this->$name = $value; // 警告は発生しません
    }
}

3. 汎用データに stdClass を使用するstdClass を介して作成された汎用オブジェクトは、このルールの対象外です。オブジェクトを純粋に一時的なデータの入れ物として使用する場合、stdClass は依然として安全で警告の出ない選択肢です。

$data = new stdClass();
$data->tempKey = 'Value'; // PHP 8.2 でも全く問題ありません

4. マジックメソッド (__set と __get) を使用する__set() を介して代入を処理すると、非推奨のチェックをバイパスできます。これにより、タイポではなく、意図的に動的データを管理していることを PHP に伝えます。

class FlexibleConfig {
    private array $settings = [];

    public function __set($name, $value) {
        $this->settings[$name] = $value;
    }

    public function __get($name) {
        return $this->settings[$name] ?? null;
    }
}

$config = new FlexibleConfig();
$config->api_key = 'secret'; // 警告なしで動作します

修正の確認簡単な CLI テストを実行して、修正を確認します。警告が表示されずに "Done" と表示されれば成功です:

php -r 'class T { public $p; } $t = new T(); $t->p = 1; echo "Done";'

既存のファイルを変更する場合は、必ず構文チェック(Lint)を実行してください。属性の追加中に構文エラーが発生していないかを確認できます:

php -l src/Models/User.php

最後に、実際のログを監視して、警告が止まったことを確認します:

tail -f /var/log/php-fpm/error.log | grep "dynamic property"

本番環境でのヒント- PHPStan で監査する: 静的解析レベルを 6 以上に設定してください。サーバーに触れる前に、動的プロパティの使用箇所をすべて指摘してくれます。- 問題を隠さない: php.iniE_DEPRECATED を抑制することは、エンジンの警告灯にガムテープを貼るようなものです。今日はしのげても、PHP 9.0 がリリースされたときに致命的なクラッシュに直面することになります。- 依存関係を確認する: vendor フォルダ内でエラーが発生している場合は、composer update を実行してください。Laravel や Symfony などの主要なフレームワークは、数ヶ月前にこれらの問題を修正済みです。

Related Error Notes