統計を見ると今でもPHP5.2系統で運用されているWebsiteは多数あるらしい。
なので「PHP5.2でも使えるように作れ」と依頼されることがある。正直、あまり楽しい作業ではないのだが、多少マシになる方法を考えてみた。
基本はPHP5.2に合わせて作ること
5.2では5.3の機能は当然ながら使えない。
- 無名関数/クロージャ
- 名前空間
- constキーワードによるグローバル定数定義
- 静的遅延束縛
- SPLの一部
こういったものは使わないようにする。基本的に、5.2で動くコードは(グローバル関数が重なったりしない限りは)5.3でも動くはずである。
無名関数/クロージャ
名前ありの関数かメソッドを作って対処する。
名前空間
モダンなPHPフレームワークではPSR-0に従ったクラス名を付けることが常識になっている。ざっくり要約すると↓のようなルールになる。
\Vendor\Hoge\Fuga_Hoo\Klass_Hoo
みたいなクラス名なら、ディレクトリ上は
Vendor/Hoge/Fuga_Hoo/Klass/Hoo.php
として配置する
PHP5.2ではそもそも名前空間が使えないため、厳密にこれを守ることはできない。PEARなどと同じく、アンダースコア区切りを利用して疑似的に名前空間を作る。
Vendor_Hoge_Fuga_Klass
というクラス名ならば、ディレクトリ上は
Vendor/Hoge/Fuga/Klass.php
として配置する
class_alias()を使ってPHP5.3でも使いやすく
以上を守ると、ものすごく長いクラス名を付けなければならなくなる。
Zend Framework1やPEARを見るとげんなりすると思う。
名前がやたら長いのはライブラリの使い勝手の悪さに直結する。
5.3なら、通常は何か名前空間を設定してコードを書くと思うのだけれど、名前空間に対応していないライブラリはインポートするのが面倒になるという弊害もある。
<?php
//ライブラリが用意しているクラス名がこんなのだったとする
class Vendor_Super_Ultra_Hyper_Klass {}
class Vendor_Super_Ultra_Hyper_Hoge {}
<?php
//利用する側はこんなコードになる
namespace Acme\MyApp;
use Vendor_Super_Ultra_Hyper_Klass as Klass;
use Vendor_Super_Ultra_Hyper_Hoge as Hoge;
//use ... //クラスが他にもあればひたすらuse文が続く
class Foo {
//...
// useを書かないのであれば、\Vendor_Super_Ultra_Hyper_Klass と毎回書くことに。。
//...
}
もともと名前空間付きでクラス名が設定してあれば、適当なところまでインポートすればよい。こういうのが理想だと思う。
<?php
//ライブラリがこんなクラス名で作ってあれば…
namespace Vendor\Super\Ultra\Hyper;
class Klass {}
class Hoge {}
<?php
//使う方
namespace Acme\MyLibrary;
use Vendor\Super\Ultra\Hyper;
class Foo {
function hoge() {
$klass = new Hyper\Klass;
$hoge = new Hyper\Hoge;
}
}
//use文も少なくて済むし、名前の長さも許容範囲ですね!
ここで、PHP5.3から導入されたclass_aliasという関数に注目する。これを使うとクラスに別名を付けることができる。
まず、polyfillをしておく。
<?php
if (! function_exists('class_alias')) {
function class_alias(){}
}
この状態で、クラス定義を以下のように書けば、PHP5.3では名前空間を活用したクラス名が使えて、PHP5.2でも長いクラス名だけは動くようになる。
<?php
class Vendor_Super_Ultra_Hyper_Klass {
//...
}
class_alias('Vendor_Super_Ultra_Hyper_Klass', 'Vendor\Super\Ultra\Hyper\Klass');