Nette RobotLoader
RobotLoader は、第三者のライブラリも含めてアプリケーション全体に、クラスの自動読み込みの心地よさを与える道具です。
- すべての
requireの文をなくします - 必要なスクリプトだけを読み込みます
- ディレクトリやファイルの名前に厳しい決まりを求めません
- きわめて速い
- キャッシュを手で更新する必要はなく、すべて自動的に起こります
- 成熟していて安定し、広く使われているライブラリ
ですから、おなじみのこうしたコードのかたまりは忘れられます。
require_once 'Utils/Page.php';
require_once 'Utils/Style.php';
require_once 'Utils/Paginator.php';
// ...
インストール
RobotLoader は単独のファイル
RobotLoader.phpとしてダウンロードでき、スクリプトで require
して取り込めば、すぐにアプリケーション全体の心地よい自動読み込みを楽しめます。
require '/path/to/RobotLoader.php';
$loader = new Nette\Loaders\RobotLoader;
// ...
Composerでアプリケーションを作っているなら、次のように入れられます。
composer require nette/robot-loader
使い方
Google のロボットがウェブのページを巡って索引を作るのと同じように、RobotLoaderはすべての PHP のスクリプトを歩き回り、そこで見つけたクラス、インターフェース、トレイト、enum を記録します。そしてその結果をキャッシュに保存し、次からのリクエストで使います。あなたが指定するのは、どのディレクトリを調べるかと、キャッシュをどこへ置くかだけです。
$loader = new Nette\Loaders\RobotLoader;
// RobotLoader が索引を作るディレクトリ(下位のディレクトリも含みます)
$loader->addDirectory(__DIR__ . '/app');
$loader->addDirectory(__DIR__ . '/libs');
// キャッシュを 'temp' のディレクトリに置きます
$loader->setTempDirectory(__DIR__ . '/temp');
$loader->register(); // RobotLoader を有効にします
これだけです。この時点から require
を使う必要はありません。素晴らしいでしょう。
索引を作っている最中に同じクラス名が重なっていると、RobotLoader は例外を投げて知らせます。RobotLoader は、知らないクラスを読み込む必要が出たときにキャッシュも自動的に更新します。本番のサーバーではこれを切ることをおすすめします。キャッシュをご覧ください。
RobotLoader にあるディレクトリを飛ばさせたいなら、$loader->excludeDirectory('temp')
を使います(何度でも呼べますし、複数のディレクトリを渡せます)。
既定では、RobotLoader は .php
の拡張子のファイルだけを調べます。ほかの種類のファイルにも索引を作らせたいなら、形の配列を持つ
$acceptFiles のプロパティを変えます。
$loader->acceptFiles = ['*.php', '*.inc'];
$ignoreDirs
のプロパティも同じように、調べるときにいつも飛ばされるディレクトリの形を持ちます(既定は
.*、*.old、*.bak、*.tmp、temp)。
既定では、RobotLoader は PHP のファイルの誤りを ParseError
の例外を投げて知らせます。これは $loader->reportParseErrors(false) で抑えられます。
内側では、register() が tryLoad() メソッドを PHP
の自動読み込みの連なりに差し込みます。PHP
が知らないクラス、インターフェース、トレイト、enum を必要とするたびに、その名前が
$loader->tryLoad($type) へ渡され、それが合うファイルを見つけて取り込みます。
Nette Application
Nette Application の中では、Bootstrap.php の立ち上げのファイルで $configurator
のオブジェクトを使うので、用意をもっと簡単にできます。
$configurator = new Nette\Bootstrap\Configurator;
// ...
$configurator->setTempDirectory(__DIR__ . '/../temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->addDirectory(__DIR__ . '/../libs')
->register();
PHP のファイルの解析器
RobotLoader は、自動読み込みの機能を使わずに、PHP のファイルの中のクラス、インターフェース、トレイト、enum を見つけるためだけにも使えます。
$loader = new Nette\Loaders\RobotLoader;
$loader->addDirectory(__DIR__ . '/app');
// クラス/インターフェース/トレイト/enum を探してディレクトリを調べます
$loader->rebuild();
// クラス => ファイル名 の組の配列を返します
$res = $loader->getIndexedClasses();
こうした使い方でもキャッシュを活かせます。おかげで変わっていないファイルは調べ直されません。
$loader = new Nette\Loaders\RobotLoader;
$loader->addDirectory(__DIR__ . '/app');
// キャッシュを 'temp' のディレクトリに置きます
$loader->setTempDirectory(__DIR__ . '/temp');
// キャッシュを使ってディレクトリを調べます
$loader->refresh();
// クラス => ファイル名 の組の配列を返します
$res = $loader->getIndexedClasses();
キャッシュ
RobotLoader はキャッシュを賢く使うので、とても速く働きます。
開発中は、それが裏で動いていることにほとんど気づきません。クラスやファイルが作られたり、消されたり、名前を変えられたりすることを見込んで、キャッシュを絶えず更新します。そして変わっていないファイルは調べ直しません。
逆に本番のサーバーでは、ファイルは変わらないので、$loader->setAutoRefresh(false)
でキャッシュの更新を切ることをおすすめします(Nette Application
では自動的にそうなります)。同時に、新しい版をホスティングへ上げるときにはキャッシュを消す必要があります。
キャッシュがまだないときの最初のファイルの走査は、大きめのアプリケーションでは当然しばらくかかります。RobotLoader にはキャッシュスタンピードへの守りが組み込まれています。これは、本番のサーバーで同時に来た大量のリクエストが RobotLoader を動かし、キャッシュがまだないのでそのすべてがファイルを調べはじめ、サーバーに過大な負荷をかけかねない状況のことです。幸い RobotLoader は、同時に複数のリクエストが来たとき、最初のスレッドだけがファイルの索引を作ってキャッシュを用意し、ほかは待って、そのあと作られたキャッシュを使うように働きます。
PSR-4
今どきは、PSR-4 を守りながら Composer
による自動読み込みを使えます。かみ砕いて言えば、名前空間とクラス名がディレクトリの構造とファイル名に対応するしくみです。たとえば
App\Core\RouterFactory は /path/to/App/Core/RouterFactory.php のファイルにあります。
RobotLoader は決まった構造に縛られないので、ディレクトリの構造を PHP の名前空間とぴったり合わせたくない場面や、歴史的にそうした決まりを使っていないアプリケーションを開発するときに役立ちます。両方の読み込み器を一緒に使うこともできます。
新しい版へ上げるなら、アップグレードのページをご覧ください。