PHP Manual

PHPでクラスをオートロードする

09. 02. 2020

PHPスクリプトをプログラミングするとき、コードを多くのファイルに分割し、すべてのパーツを利用できるようにするために、 `include` や `require` 、できれば `require_once` を何度も呼び出して読み込みます。

コードでは次のようになります。

require_once 'ルーター.php';
require_once 'ページ.php';
require_once 'Paginator.php';

この方法の主な欠点は、プログラマーが常にすべてがロードされていることを確認しなければならないことです。しかし、彼がたくさんロードすると、不必要にパフォーマンスが低下し、何度もディスクに到達してしまう。つまり、マニュアルソリューションには問題しかないのです。

ネイティブオートローディング

幸いなことに、PHPではいわゆるクラス・オートローディングをネイティブにサポートしています。これは、クラスファイルが最初に必要になったとき(通常はインスタンスが最初に作成されたとき)にのみ読み込まれるコード内のロジックです。

そうすると、簡単な実装は次のようになります。

spl_autoload_register(function (string $className): void {
include 'src/' . $className . '.php';
});
$obj = new MyClass1();
$obj2 = new MyClass2();

MyClass1クラスのインスタンスを作成するとき、spl_autoload_register関数はsrcディレクトリからMyClass1.php` ファイルを読み取ります。この実装では、各クラスがクラス名またはインターフェース名で呼ばれる個別のファイルにあることを想定しています。

より複雑なオートローディングのケース

実際のアプリケーションでは、オートロードを複雑化させるなど、多くの不都合な状況が起こり得ます。

  • クラスまたはインターフェイスが全く存在しない
  • ファイルはすでに一度読み込まれています
  • 同じファイルに複数のクラスまたはインターフェイスが存在する
  • クラスまたはインターフェースのパスが名前と一致しない
  • クラスやインターフェースの位置が時間と共に変化する

しかし、これらすべてのソリューションを独自にプログラムする必要はなく、一度設計した既存のソリューションを利用することができます。

Composer を使用している場合、おそらくそのネイティブのオートローディングも使用していることでしょう。これは、パッケージをインストールする際に、Composerが自動的にクラスマップを生成するからです。

そして、コードの冒頭(通常は index.php 内)で、次のように使用するだけです。

require __DIR__ . '/vendor/autoload.php';

しかし、オートローディングは composer dump コマンドが呼ばれたときに一度だけ生成されるので、アプリケーションが変更されるたびにオートローディングを再生成する必要がある。

RobotLoader - 開発のためのエレガントなソリューション

ローカルで開発する場合、私は nette/robot-loader パッケージをとても気に入っています。これは、ディレクトリ構造を自動的にトラバースして、クラスの位置をキャッシュするものです。そのため、クラスをロードする場合、まずキャッシュを探し、存在しない場合のみ、自動的にプロジェクトのインデックスを再作成します。そのため、プログラマーはどのファイルやクラスがどこにあるのかを全く把握する必要がなく、ただプログラムを組むだけでよいのです。

Composer経由でのインストール。

composer require nette/robot-loader

機能の基本的な説明は、ドキュメント自体に記述されています。

GoogleのロボットがWebページをクロールしてインデックスを作成するのと同様に、 RobotLoaderはすべてのPHPスクリプトをクロールして、どのクラス、インターフェース、 traitsを発見したかを記録します。そして、その調査結果をキャッシュし、次のリクエストで使用する。そのため、どのディレクトリをクロールし、どこにキャッシュするかを指定するだけでよいのです。

すると、非常に使い勝手がよくなります。

$loader = new Nette\Loaders\RobotLoader;
// RobotLoader がインデックスを作成するディレクトリを追加します。
$loader->addDirectory(__DIR__ . '/アプリ');
$loader->addDirectory(__DIR__ . '/libs');
// キャッシュをディスクの 'temp' ディレクトリに設定する。
$loader->setTempDirectory(__DIR__ . '/temp');
$loader->register(); // RobotLoaderを起動する

loader->setAutoRefresh(true or false)` を設定すると、RobotLoader が新しいクラスに出会ったときにファイルのインデックスを再作成するかどうかを決定します。本番サーバーでは、この機能を無効にする必要があります。

これでもう、オートローディングに悩まされることはないでしょう。

複合ソリューション

実際のプロジェクト開発では、複合的なソリューションを使っています。

実際の動作としては、インストールしたパッケージをComposerのオートロード(非常に効率的)でロードし、これによりvendorディレクトリのすべてのクラスのロードを解決しています。

そして、特定のプロジェクトのコードは app ディレクトリに置かれ、RobotLoader を使っていくつかのクラスだけをオートロードするようにします。重要なのは、具体的なアプリケーションを常にできるだけ小さくし、できるだけ既製のパッケージを使用することです。これは、再利用性を大いに促進します。

構成はこんな感じです。

/app
Bootstrap.php <-- konfigurace
/model
UserForm.php <-- projektové třídy
RegisterFactory.php
...
/vendor
... <-- knihovny
/www
index.php <-- inicializace

オートローディングのテスト

すべてのファイルが常に読み込まれるわけではなく、問題が見つかることもあります。

デバッグには、get_included_files() 関数をお勧めします。

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
3.
Status:
All systems normal.
2024