PHP

【PHP】spl_autoload_registerとオートロード

パーフェクトPHPを読んでおり、第7章を読んでいる所です。

この章では独自フレームワークの作成を行う章であり、PHPをLaravelから入り、Laravelを更に理解したい僕には第7章は最高の章です。

そこで出てきた『spl_autoload_register』という物について理解した事をまとめたいと思います。

この記事では、PHPのspl_autoload_registerとオートロードについて解説します。

結論から先に言うと

『spl_autoload_register』とは

クラスからインスタンスを生成しようとした場合、そのクラスが未定義であれる事をフックに登録しておいたメソッドを実行させる仕組みです。

これによりオートロードの仕組み作りに利用できる。

オートロードとは

クラスをインスタンス化するためには事前にそのクラスを定義したファイルを『require』する必要があります。

モデルなどで定義したクラスがどんどん増えていったり、自分で作成したフレームワークのクラスが膨大になって行くと、毎回requireするのは大変になってきます。

そこで、クラスのファイルを『どこに置いておくか』、『どんな命名で置いておくか』をルール化しておく事で、自動でクラスファイルを探しに行ってくれる仕組みをオートロードと言います。

その仕組みをPHPで作成する際に『spl_autoload_register』は役に立つのです。

spl_autoload_registerとは

そもそも『spl』とは何かというと『Standard PHP Library (SPL)』の頭文字をとったものであり、PHPの標準ライブラリという便利メソッド達のことです。

こちらのPHPの公式ドキュメントを参考にされると良いです。

公式ドキュメントの説明には次の様に書かれていました。

指定した関数を、spl が提供する __autoload キューに登録します。 キューがまだアクティブになっていない場合は、まずアクティブにします。

引用元:PHPドキュメント | spl_autoload_register

正直何かよくわかりませんでしたが、__autoloadというキューを勉強する必要があります。コードをみた方が早いと思うので実装例を見ましょう。

私の理解としては

『spl_autoload_register』はクラスをインスタンス化した場合、未定義であれば特定のメソッドを実行するためのメソッドだと理解しています。

使用例

オートロードするためのクラスを次のように作成します。

オートロードは毎回requireするのを避ける手法です。ですので、クラスを

<?php

class ClassLoader
{
 // オートロードで調べるディレクトを格納する変数
    protected $dir;
 // オートロード実行メソッド
    public function register()
    {
  // loadClassメソッドを実行する
        spl_autoload_register(array($this, 'loadClass'));
    }

 // 探索するディレクトリを登録
    public function registerDir($dir)
    {
        $this->dirs[] = $dir;
    }
    // 未定義のクラスをnewした場合呼び出される
 // $classはその時のクラス名
    public function loadClass($class)
    {
  // 登録していたディレクトリにインスタンス化しようとしたクラスファイルが存在しているか確認
        foreach($this->dirs as $dir){
            $file = $dir. '/' . $class . '.php';
    // 存在していればrequireし、未定義エラーを回避
            if(is_readable($file)){
                require $file;

                return;
            }
        }
    }
}

?>

registerメソッド内で、クラスが未定義の場合に実行するメソッドを定義しています。

今回の場合では未定義の場合、『loadClass』を実行します。

次にこの『ClassLoader』を利用例を示します。

<?php
require 'core/ClassLoader.php';
$loader = new ClassLoader();
// coreとmodelsディレクトリを探すように登録
$loader->registerDir(dirname(__FILE__).'/core');
$loader->registerDir(dirname(__FILE__).'/models');
$loader->register();
// core/Sample1.php
// models/Sample2.php
$sample1 = new Sample1;
$sample2 = new Sample2;
?>

ClassLoaderクラスをrequireし、クラス宣言時に未定義であれば『/core』もしくは『/models』を探索するようにセットしておきます。

その後Sample1とSample2をnewして見ます。すると、Sample1.phpやSample2.phpをrequireしていないにも関わらずインスタンス化に成功します。

これは未定義の場合、loadClassメソッドが実行され、設定して置いたディレクトリに、『クラス名.php』が存在するか探索し、存在すればrequireをしているからです。

これが実現しているのは

  • クラスファイルの命名が『クラス名.php』である
  • クラスファイルが存在する場所は『/core』か『/models』

と言うルールがあるため実現できているのです。

仮に『test/Sample3.php』を作成し、『$sample3 = new Sample3』としても未定義のままに終わります。

それは『/test』探索するように設定していないからです。

$loader->registerDir(dirname(__FILE__).'/test');

のように探索するディレクトリに追加しておけば、Sample3もインスタンス化することが可能となります。

まとめ

『spl_autoload_register』について理解を深めました。

  • ファイル名 = クラス名.php
  • どのディレクトリにクラスファイルをまとめるか

と言うルールを作成することと、

『spl_autoload_register』と言うクラスが未定義をフックに実行するメソッドを定義できるメソッドを組み合わせることにより、オートロードが実現していることがわかりました。

パーフェクトPHPは本当に良書なのでPHPerであれば是非読んで見て下さい。