目次
- 経緯
- PHPのバージョンについて
- 苦行を紹介
- Case1.ここはどこ?私は誰?
- Case2.地雷原をゆく
- どのように修正していったか
経緯
2023年末、LinuxサーバーリプレースPJが発足。
デフォルトでインストールされているPHPのバージョンが上がるため、プログラムを更新しなければならなくなりました。
このバージョンアップPJを取り仕切ることになった若手PGの奮闘が誰かの参考になれば幸いです。
※コンテナ使えばよかったじゃん ← 野暮なのでなしです
※今更PHP7の話されても ← 野暮なのでなしです
PHPのバージョンについて
公式とこちらのサイトを参考に、対象バージョンのみをまとめました。
Version | 初回リリース日 | アクティブサポート期限 | セキュリティサポート期限 |
---|---|---|---|
7.4 | 2019年11月28日 | 2021年11月28日 | 2022年11月28日 |
5.6 | 2014年8月28日 | 2017年12月31日 | 2018年12月31日 |
アップ先のPHP7.4も切れてます。笑
PHP6系は開発段階で凍結されたため、5系の次が7系となります。
実質1バージョンのアップでした。
苦行を紹介
変更点の中で特に辛かった2点を紹介します。
Case1.ここはどこ?私は誰?
PHP5.6で書かれた以下のコードがあります。
class Main {
function run() {
$this->callDynamic();
$this->callStatic();
}
function callDynamic() {
$helper = new Helper();
$helper->say();
}
function callStatic() {
Helper::say();
}
}
class Helper {
function say() {
echo "My name is " . get_class($this);
}
}
この時、出力は以下のようになります。
// -> callDynamicとcallStaticが順番に呼ばれる
$main = new Main()
$main->run()
// My name is Helper
// My name is Main
ここで注目したいのは、callStatic内でHelper::say()
として呼び出された際の$thisコンテキストがMainとなっていることです。
PHP5系では、静的呼び出しをすることで呼び出し元の$thisコンテキストを引き継ぐ挙動をとります。
「Helperのsayはstatic修飾子がついていないのに、静的呼び出ししていいの?」という疑問が湧きますが、PHP5系ではエラーになりません。(ただし非推奨)
私の経験したプロジェクトではこの「非staticな関数を静的呼び出しして$thisを引き継ぐ」という方法が乱用されていました。
つまり...
class Helper {
function say() {
Helper2::say();
}
}
class Helper2 {
function say() {
Helper3::say();
}
}
呼び出し元の this コンテキストを引き継ぐので、
Helper がさらに Helper2 を静的呼び出し、さらにそこから...
(果てしなく長い旅)
あれっ、僕は誰...?
Case2.地雷原をゆく
Case1で判明した「PHP5系のダブルコロン呼び出しは$thisコンテキストを引き継ぐ」という挙動が、別の問題を生み出しているので紹介します。
先ほどのコードを少し書き換えてみます。
StaticHelperクラスのsayにstatic修飾子をつけました。
class StaticHelper {
static function say() {
echo "My name is " . get_class($this);
}
}
...ん?
staticの中に$this!?
しかも動くの!?
PHP7系からFatalErrorになりました。
もう一点、$thisコンテキストについて仕様変更がありました。
class Main {
function run() {
StaticHelper::say();
}
}
class StaticHelper {
// ダブルコロン呼び出しを想定していない関数
function say() {
echo "My name is " . get_class($this); // Fatal error!
}
}
このように非staticな関数を静的呼び出ししたとき、PHP5系まではCase1の通り呼び出し元の$thisコンテキストを引き継いていましたが、PHP7系ではFatalErrorになります。
いかなる関数でも、静的呼び出しをすることで$thisコンテキストを失うようになりました。
「非staticな関数の静的呼び出し」の蔓延していた当プロジェクトでシステムエラー祭りになったことは想像に難くないでしょう。
どのように修正していったか
ローラー作戦をやりました。
同じ経験をする方がいらっしゃるか分かりませんが、誰かの参考になれば幸いです。
手順
「インスタンスメソッドの静的呼び出し」を全て洗い出し
- PHP の Lint 様が Deprecated として青波線で出してくれた(幸)
- 出さない部分もあったため「::」で検索して目検品 → 法則性を見つける
対象となるメソッドを全行確認
- 対象メソッドが呼び出した先のメソッドは$thisを参照する?していない?
都度判断・改修
- static をつける?
- $this をバケツリレーする?
- ロジックの構造を変える? etc...
「非staticな関数の静的呼び出し」を使った途端、$this
コンテキストが失われるので、依存先の関数で$thisを参照する記述がないか、ローラーで確認します。
今だとAIがありますので、このような機械的な作業は格段にやりやすくなったでしょう。これを手動でやる労力より、会社にClaudeCodeの稟議を通す労力を費やした方が圧倒的にいいです。本当に。
以上になります。
かなり大変だったことを思い出したので誰かに見てもらいたく、記事にしました。
読みづらい部分も多かったかと思いますが、ここまで読んでくださりありがとうございました!!