オートローダの設計のポイントについて。個人的メモ。
spl_autoloader_registerの使い方についてはこちら
概要
ポイントとなるのは以下の様な感じ?
- 読み込みルールについて
- 名前空間使う?
- ベースディレクトリは1つ?複数?
- エイリアスルールの有無
- 静的コンストラクタ使うかどうか
読み込みルールについて
基本的なところはあんまり変わらないかと。
- クラス名を全部小文字に置き換える。
- 名前空間の区切りをディレクトリ区切りに置き換える。
- _をディレクトリ区切りに置き換える。
- ベースディレクトリから拡張子
.php
で読み込む。
拡張子.cls
なんてイマドキ使ってる所あるのんかしらん。うちの現場では使ってるみたいです。謎。
名前空間とか使っちゃうと,レガシーなおっちゃん達の劣等感煽るだけって可能性もあるので現場の雰囲気見てから決めましょう。
んでポイントはベースディレクトリを複数用意するか否か。この辺りが判断の分岐点。
ベースディレクトリが複数の場合
あるクラス名に対して,複数の箇所からの読み取りを試みるようなタイプ。
core/classes
ディレクトリがあって,app/classes
があって…みたいな。 ベース部分とアプリケーション部分、みたいな感じで階層化することが可能。結構便利。と同時に、いくつかの問題も。
まずクラス名を見ただけで,ファイルの場所を一意に特定できない。あとセキュリティ的な問題とか。同じクラスを使っていても参照先が違う、、、とかね。
ベースディレクトリがひとつの場合
クラス名からファイルの場所を一意に決定出来る。まぁ上の形式の逆バージョン。小規模なアプリケーションだとこちらのほうが管理楽だけど、一度作ったクラス同名で処理上書きとかするの面倒。
エイリアスルールの有無
上記の基本的なオートローダルールとは別に,再優先で適用されるエイリアスルールを設けるかどうか。これがあるとクラス名とファイル名を紐付けたくない時とか,ベースディレクトリがひとつなんだけどクラス名を変えずに参照先変えたいときとかに対処できる。
でもまぁやっぱりその分管理はややこしくなる。実装方法としてはグローバルな配列(クラスの静的プロパでも可)とかにクラス名=>パスで登録してオートローダに配列走査させる、みたいな感じになる。
静的コンストラクタ使うかどうか
静的コンストラクタ。あると便利です。実装方法としては
- インターフェイスでやる。
- ダックタイプでやる。
のどっちか。例えば__init()
とか決めてダックタイプ方式にすると静的コンストラクタの存在知らない開発者が作った__init()
とかも起動してしまう。その点インターフェイス方式は安全だけど実装がいちいち面倒。implementとか打ってる間に指つるわ。
コード
多分汎用的に使える。
call_user_func(function($base_dir){
$autoload = function($className)use($base_dirs) {
$file_name = strtolower($className);//小文字に揃えて
$file_name = str_replace(["\\","_"], DIRECTORY_SEPARATOR, $file_name);//置換して
foreach($base_dirs as $basedir){
if(is_readable($basedir . $file_name)){
include $basedir . $file_name;
break;
}
}
};
spl_autoload_register($autoload);
}, [__DIR__ . "/classes/",__DIR__."/vendor/"]);
ベースディレクトリを複数にするときにはis_readable
とかで事前にパスのチェックをすればいい。
インターフェイスで初期化する時はinstanceof
演算子とかで。ダックタイプしたい時は
if (method_exists($class, '_init') and is_callable($class.'::_init'))
{
call_user_func($class.'::_init');
}
みたいな感じで。
参考:
色んなタイプのオートローダとか紹介
http://phpmaster.com/autoloading-and-the-psr-0-standard/