先日PHP9で未定義変数が使えなくなることが決まりましたが、それのプロパティ版です。
class HOGE{
public function __construct(){
$this->a = 1; // PHP8.2以降エラー
echo $this->b; // PHP9.0以降エラー
}
}
このソースコード、PHP8.1まではE_WARNINGが出るものの動作はします。
しかしこのうち、未定義プロパティへの代入$this->a=1
はPHP8.2で禁止されました。
そしてPHP9では、未定義プロパティの取得$this->b
が禁止されることとなります。
以下は該当のRFC、Undefined Property Error Promotionの日本語訳です。
Undefined Property Error Promotion
Introduction
未定義プロパティとは、まだ定義されていないプロパティのことです。
未定義プロパティにアクセスするとUndefined property <className>::$varName
のE_WARNINGが表示され、その値はNULLであるかのように扱われますが、実行が中断されることはありません。
しかし、これは意図しない挙動である可能性が高いでしょう。
未定義プロパティへのアクセスは、かつてはE_NOTICEでしたが、Reclassifying engine warningsのRFCへの対応の結果、PHP8.0においてE_WARNINGになりました。
PHP9がリリースされる頃には、未定義プロパティへのアクセスがE_WARNINGになってから既に5年以上が経つことになります。
Proposal
このRFCは、次のメジャーバージョンアップにおいて未定義プロパティへのアクセスを禁止し、アクセスした場合はError例外をスローすることを提案しています。
未定義である可能性を考慮せずプロパティにアクセスした際に発生するもので、Undefined property <className>::$varName
のE_WARNINGが起こるか否かで区別されます。
isset() / empty() / null合体演算子等は、プロパティが未定義であるかを考慮するため、本RFCによる影響はありません。
マジックメソッド__get
が存在する場合は現在と同じ動作となり、未定義プロパティへのアクセスはエラーにならず__get
に転送されます。
Considerations
PHPは伝統的に、データ構造内の未定義値へのアクセスについては非常に緩い態度を取っていました。
値を格納する場所としては、主に以下の3か所があります。
・ 変数 スタックフレーム
・ プロパティ HashTable
・ 配列 バケツ
このうち変数については、Undefined Variable Error PromotionによってPHP9.0でエラーになる予定です。
次のターゲットがプロパティになるのは自明なことでしょう。
また未定義プロパティへの書き込みはDeprecate dynamic propertiesにおいて禁止されました。
PHP9.0以降、#[AllowDynamicProperties]
アトリビュートを指定しないかぎりエラーになります。
未定義プロパティへの書き込みがエラーになるのであれば、未定義プロパティからの読み取りも同じようにエラーになるのが自然な成り行きというものです。
なお、書き込みのルールについては暗黙的な例外があり、それはstdClass
です。
stdClass
は未知のプロパティを保持することを目的としたクラスであるからです。
たとえば配列をオブジェクトにキャストしたり、json_decode
したときに生成されます。
ユーザ定義クラスに対して未定義プロパティを読み込むのはほとんどの場合プログラマのミスですが、たとえばJSONを扱うときに以下のようなコードを書くのはよくあることでしょう。
if ($obj->name) {
echo "Hello " . $obj->name;
}
これは$obj->name
が未定義である場合はE_WARNINGが発生するのでお勧めはできませんが、値はnullと評価されるため処理自体は実行されます。
このRFCが採択された場合、今後はisset
やempty
等を用いて、以下のように書き直す必要があります。
if (isset($obj->name)) {
echo "Hello " . $obj->name;
}
このRFCでは、stdClass
についても例外を設けず、読み取りについては一貫してエラーを出します。
Backward Incompatible Changes
undefined property
のE_WARNINGが発生する方法で未定義のプロパティにアクセスしている場合、PHP9以降ではエラーになります。
Proposed PHP Version(s)
PHP9.0。
ターゲットのバージョン指定としては類を見ないものですが、このRFCの意図として、この変更をあらかじめ告知しておくことで開発者へのコード修正の期間を最大限に増やす目的があります。
次のマイナーバージョンアップにおいて、PHP9においてエラーになる旨の警告メッセージを表示します。
Voting
投票期間は2022/04/22から2022/05/05まで。
このRFCは、賛成31反対5の賛成多数で受理されました。
感想
Q:どうしてUndefined Variable Error Promotionで一緒にエラーにしなかったの?
A:エラーメッセージがWarning: Undefined variable $varname
ではなかったからじゃよ。
Undefined Variable Error PromotionのRFCでは、エラーになるのはメッセージがWarning: Undefined variable $varname
である場合だけだと定義していました。
プロパティの場合、メッセージがWarning: Undefined property: HOGE::$varname
となるので対象外だったというわけですね。
そんなわけで、未定義変数および未定義プロパティへの読み取りアクセスはPHP9以降エラーになります。
定義されていない値へのアクセスは今後もびしばし厳しくなることが予想されます。
そのようなコードは書かないようにしましょう。
といっても、まだ残っている未定義値へのアクセスって配列インデックスくらいですかね。
それに現在でも未定義値へのアクセスはE_WARNINGになるので、普通に書いているかぎりでは対処しているはずです。
これが影響するのは、主にPHP5時代から残っているような古き悪きコードで、そしておそらくそういうコードはそもそも他の変更で既に動かなくなっていることでしょう。