PHP

PHP で、spl_autoload_register を使って、require_once 地獄を脱出しよう

More than 1 year has passed since last update.

目的

require_once 地獄を脱出したい!
require_once は、実行順に依存するため、たとえば PHPUnit で起こらなかったのに、ブラウザで実行したらクラスがないよと怒られたり、ということがありえます。

spl_autoload_register() とは

http://php.net/manual/ja/function.spl-autoload-register.php

通常、

$user = new User();

などとして、そのクラスがない場合、

Fatal error: Class 'User' not found in ...

などとエラーになります。
その際、 spl_autoload_register() を使ってメソッドを登録しておけば、エラーが出る前に、そのクラス定義を探す最後の救済メソッドを実行できます。
それでも見つからなければおなじみのエラーが出ます。

PHPのバージョンは?

  • PHP 5.0.x の方
    • spl_autoload_register() はありません。代わりに __autoload() が使えますが、そんな開発やる前に転職しましょう。 __autoload() のことなど忘れてしまえ。
  • PHP 5.1.2 以上の方
    • spl_autoload_register() はサポートされていますが、オレオレフレームワークであっても、 このようなクラスは自作せず、 Composer のautoload などを利用することを考えましょう。
    • また、PHPのサポート期限はバージョン毎に定められています。特にセキュリティ上の観点から、サポート中のバージョンを利用しましょう。 -> http://php.net/supported-versions.php

モダンPHPer へのさらなる利点

PHP5.3以上ですと、

  • 名前空間が利用できる
  • オートロード関数内で起きた例外もキャッチできる
  • 無名関数を登録することも出来る
  • 第2引数 prepare を使うことにより、オートロード関数を読み込む順番を制御できる。

お得ですね。

実装例

それでもオレオレ規約でクラスたちを管理したい方用の、実装例が以下になります。

ClassLoader.php
<?php

/**
 * Classが定義されていない場合に、ファイルを探すクラス
 */
class ClassLoader
{
    // class ファイルがあるディレクトリのリスト
    private static $dirs;

    /**
     * クラスが見つからなかった場合呼び出されるメソッド
     * spl_autoload_register でこのメソッドを登録してください
     * @param  string $class 名前空間など含んだクラス名
     * @return bool 成功すればtrue
     */
    public static function loadClass($class)
    {
        foreach (self::directories() as $directory) {
            // 名前空間や疑似名前空間をここでパースして
            // 適切なファイルパスにしてください
            $file_name = "{$directory}/{$class}.php";

            if (is_file($file_name)) {
                require $file_name;

                return true;
            }
        }
    }

    /**
     * ディレクトリリスト
     * @return array フルパスのリスト
     */
    private static function directories()
    {
        if (empty(self::$dirs)) {
            $base = '/path/to/application/dir';
            self::$dirs = array(
                // ここに読み込んでほしいディレクトリを足していきます
                $base . '/controllers',
                $base . '/models'
            );
        }

        return self::$dirs;
    }
}

// これを実行しないとオートローダーとして動かない
spl_autoload_register(array('ClassLoader', 'loadClass'));

使い方

さあ、今まで書いた require_once とサヨナラです。

require_once '/path/to/ClassLoader.php';