PHP では使うクラスを予め宣言する、というルールがあります。
これを忘れていると、実行時にエラーが表示されます。
Fatal error: Uncaught Error: Class 'XXXXXX' not found in /Sample/Test.php:26 Stack trace: #0 {main} thrown in /Sample/Test.php on line 26
C# などを経験してると、これは非常にストレスです。(C# では宣言をする必要性も少なく、右クリックで using を自動的に挟めるなど便利な環境が揃っているため)
また、このルールに慣れ親しんだ人でも、
- 大規模な開発案件で、1ソースに数十の require が並ぶ
- テストログ吐くためだけに require しないといけない
- 後で使わなくなったクラスの require がどれだかわからない -> 知らない間に実行コスト増加
このように色々としんどい要素が多い。このしんどさを解消しましょう。
ソースコード
autoLoader.php
<?php
class autoLoader
{
protected $dirs;
function __construct($dir = null)
{
if ($dir != null)
{
$this->dirs[] = $dir;
}
}
public function Register()
{
spl_autoload_register(array($this, 'autoLoad'));
}
public function AddDirectory($dir)
{
$this->dirs[] = $dir;
}
private function autoLoad($className)
{
foreach ($this->dirs as $dir)
{
$file = $dir . '/' . $className . '.php';
if (is_readable($file))
{
require $file;
return;
}
}
}
}
?>
テスト
testClass.php
<?php
class testClass
{
public static void exec()
{
echo 'exec class</br>';
}
}
?>
sample.php
トップコードに autoLoader を入れておくと、以後呼び出されるクラスファイルは全て require(_once) が必要なくなります。
<?php
require("autoLoader.php");
// sample.php と同じパスに、全ての php があるとする
$autoLoader = new autoLoader(dirname(__FILE__));
// 他にファイルを探すディレクトリがある場合、AddDirectory で追加する
// $autoLoader->AddDirectory("....");
$autoLoader->Register();
// require がなくても動く
testClass::exec();
?>
解説
spl_autoload_register によって「インスタンス生成時、require されていないクラスであれば呼ばれる関数」を定義します(autoLoad)。
autoLoad では、読み込まれていないファイルパスを自動生成し、require します。
(構造的に、検索するディレクトリが多いほど実行時間がかかります)
注意点
ファイル名=クラス名にしておく必要があります。ゆえにこういうのはダメです。
ファイル名:test_sample.cs、クラス名:TestSample
メソッド autoLoad を改造すればこういうパターンも有りにすることはできますが、実行コストが上がってしまうのでちょっと…。
実行速度
さすがに require を直接書くより単純速度は遅くなります。(サーバーのファイル検索速度に依存するでしょう)
とはいえ、無駄なファイルを require せずに済むロス回避の面もありますし、例えばこんな感じで動的にクラスを呼んでる場合、require を1つで済ますことができ、かえって速度上昇するケースもあるかもしれません。
// テーブルは50テーブルくらいある。require であれば 50 記述する必要がある
call_user_func($tablename. '::GetRecordCount', $search_id)
総じて、余程 require が絶大なパフォーマンスを誇るケースでなければ、こちらの方がいいんじゃないかと思います。


