Help us understand the problem. What is going on with this article?

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

More than 3 years have 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';
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away