ついにこの日が来てしまったようです。
PHPのユルさの象徴のひとつとして『未定義変数に普通にアクセスできる』というものがあります。
echo $a; // Notice: Undefined variable: a
大抵の言語ではエラーや例外で落ちますが、PHPでは処理が中断することはありません。
警告は出ますが、最もエラーレベルの低いE_NOTICEです。
が、PHP8.0でこの挙動が変わることになりそうです。
Reclassifying engine warningsというRFCが提出され(提出者はいつものNikita)、2019/09/26まで投票中です。
これは様々な警告のエラーレベルを変更しようというRFCなのですが、ここではそのうちのUndefined variable、Undefined array indexに絞って紹介してみます。
RFCでもこれらの項目は特別に分けられていますしね。
Reclassifying engine warnings
変更には投票の2/3の賛成が必要です。
Proposal
警告や例外には主にE_NOTICE、E_WARNING、Error例外の3段階がありますが、一部の警告についてエラーレベルを変更します。
ただし上げる場合でも1段階しか上げません。
現在E_NOTICEの警告のエラーレベルを上げる場合はE_WARNINGに上げるだけで、いきなり例外まで上げるとはない、ということです。
ただしUndefined variableのみ例外。
Undefined variable
大抵の場合、未定義変数へのアクセスは重大なバグです。
現在のE_NOTICEというとても軽い警告は、register_globals
のような外から変数を定義してしまうことができていたPHP暗黒時代の遺物です。
理想的には、未定義変数へのアクセスはコンパイルエラーになるべきですが、PHPの性質上コンパイル時に全ての分析を行うことはできないため、このRFCでは代わりにError例外にすることを提案します。
しかしながら、例外にするとこれまでのように警告を無視することができなくなるため、大量の警告を抑制して運用しているようなレガシーコードは多大な改修が必要となります。
また一部には、未定義変数の使用は正当なコーディングスタイルであるとさえ考えている過激派も存在します。
これらの理由のため、Error例外にするか、E_WARNINGにするか、E_NOTICEのままにするかの個別投票を行います。
2019/09/14現在、Error例外が22票、E_WARNINGが8票、E_NOTICEのままが4票で、おそらくError例外になります。
Undefined array index
未定義変数や未定義プロパティと同様、未定義の配列キーへのアクセスは、モダンPHPではプログラミングのエラーであるはずです。
しかし、変数やプロパティは主に静的に定義されるのに対し、配列のキーは動的に生成されることが多いため、全く同じ扱いをすることは難しいかもしれません。
JavaScriptのような一部の言語は、未定義の配列キーへのアクセスをエラーにしませんし、そのような操作をサイレントに実行します。
PHPでも主流ではないものの、同じようなコーディングスタイルを取る者たちがいて、彼らは未定義の配列キーへのアクセスが抑制可能な警告であることを願っています。
従って個別投票により、E_WARNINGに上げるか、E_NOTICEのままかを決定します。
2019/09/14現在、E_WARNINGが23票、E_NOTICEのままが13票で拮抗しています。
感想
私としては、仕事とかで書くちゃんとしたコードは常にerror_reporting(-1)
と書いているので、業務上は影響ありません。
ただ使い捨てで適当に書き散らすコードなんかは警告が出てても一回動けばいいやとかやったりしているのですが、今後はそのような手抜きが許されなくなります。
書いたらなんかとりあえず動く、という他言語に対するPHPの大きな利点(にして同時に欠点)を投げ捨ててまで得られるものがあるのかというと、個人的には少々疑問に感じます。
巷に溢れるテキトーなコードも大半が即死し、PHPを始める敷居が大きく上がってしまうことは間違いありません。
テキトーなコードなんて死滅してもいい?
むしろ絶滅させるべき?
みんな正しいコードを書くべき?
正しいコードしか許されないべき?
未定義変数アクセスの例外化は、プログラミング言語として正しい方向性でしょう。
しかし世の中、正しければ勝てるというわけでもありません。
使用前の変数宣言なんて難しいコーディング、誰も彼もができるわけではないのです。
この正しい変更は、入口が狭まるというデメリットを上回るメリットを果たして得られるのでしょうか。
あと最大の問題点として、ゴルフが不可能になります。
こりゃ致命的だ。
回避策はあるか?
レガシーコードではerror_reporting(E_ALL~E_NOTICE)
なんてことをやって警告の通知を無視していたわけですが、例外になるとこれが無視できなくなります。
プログラムを変更せずに回避する方法はないでしょうか?
PHPには例外の挙動を変更するset_exception_handlerという関数があります。
しかし、これは実のところ単にプログラム全体を囲むtry/catch
なので、発生自体を無視したり、発生箇所に戻って先に進むといったことはできません。
ということでちょっと思いつかないですね。
誰かがきっと考えてプルリクしてくれるはず。
うん、まあ、そもそも例外が出ないように修正しろよって話ですが。