<?php
require_once __DIR__ . '/vendor/autoload.php';

上記のように、エントリポイントであるPHPファイルに記述するだけで、クラスのオートロードをしてくれるようになり、requireだらけのコードとさよなら出来るcomposerのオートローダ。

便利ですね。

どういう仕組みでこの便利さが実現されているのか、少し追ってみました。

根幹はSPL関数が提供するオートロード機構である

クラスのオートロード機構をすべてまるごとcomposerがフルスクラッチで提供しているわけではありません。
PHPが提供しているSPL関数によるクラスのオートローディング機構を、composerが利用する形となっています。

SPLのオートロード機構とは

詳細は上記のマニュアルに書いてあるとおりです。

spl_autoload_register()関数を使って、クラスが見つからなかった場合の最終手段としてのコールバックを登録しておくと、それを実行してくれるというものです。

最後の砦ですね。

composerによるクラスのオートローディングも、このspl_autoload_register()を使用しています。

composerがどのようにオートローディングを実現しているか

以上を踏まえて、composerがどのようにオートローディングを実現しているかをまとめます。
(オートローディングの流れが主旨であるため、composer.jsonの基本的な設定等には触れません。)

1. composer install 実行時にクラスマップファイルが生成される

composer installが実行されると、オートロード用のいろいろなファイルが生成されますが、クラスマップファイルもこの時に生成されます。

vendor/composer/autoload_classmap.phpというファイルがそれです。中身はたとえば以下のようになっています。

<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Bar' => $baseDir . '/app/Bar.php',
    'Foo' => $baseDir . '/app/Foo.php',
);

composer install時に、設定をもとに探索したクラス名とクラスファイルパスの連想配列を返してくれるファイルです。

2. ‘/vendor/autoload.php’をrequireすると行われること

さて、1行書けばオートローディングが実現される、require '/vendor/autoload.php';についてです。

/vendor/autoload.phpをrequireすると、/vendor/composer/autoload_real.phpというファイルがrequireされます。

そして、上記ファイルで定義されているクラス(このクラスは動的に定義されます。)のstaticメソッドであるgetLoader()をコールし、その結果を返します。

getLoader()メソッドでは、\Composer\Autoload\ClassLoaderクラスのインスタンスを生成し、このインスタンスに生成済みのクラスマップ等をプロパティとしてセットします。
そして、例のspl_autoload_registerを使用して、このインスタンスのloadClass()メソッドをコールバックとして登録します。

3. requireなしでクラスが参照(new しようとしたり)された際に行われること

いよいよ、requireなしでおもむろに$foo = new Foo;などと書いた時の動作についてです。

requireされてないので、クラスは見つかりません。よって、最終手段であるSPLのオートローディング機構を探索します。

この際に、上記のloadClass()メソッドが、参照されたクラス名を受け取り、インスタンスが保持しているクラスマップからクラスファイルのパスを取得し、それをincludeします。
これにより、クラスが参照されようとしたまさにそのタイミングで、クラスがロードされるというわけです:tada:

シンプルですね。


レガシーなアプリケーションに、composerのオートロード機構を導入した際、既存のrequire類を削除する必要があるのかという質問を受けました。

結論は、削除しなくても問題はないですよね。

オートロードは最終手段ですので、requireされていたら出る幕のない機能です。

ただ、せっかくオートロード機構を導入するわけなので、不要なrequire類は削除してオートロード機構を使うように統一したほうが以下の様なメリットがありそうです。

  • 単純にコードがすっきりしますよね。コードの冒頭の大量なrequireや、至る所に出現する単発requireと、さようなら:+1:
  • requireに書くパスが環境によって通らなかったりして本番だけでコケた。みたいな惨事と、さようなら:+1:
  • さもオートロード機構を備えているような雰囲気を持っているがホントは持ってないレガシーアプリケーションに手を加える時に、どっちだっけ?怖いからとりあえずrequire書こう。え?みたいなことと、さようなら:+1:
  • etc…