Laravelを勉強していて、初めてphpの
「autoload(オートロード)」と言うものに触れたので、学んだことをメモ。
autoload(オートロード)とは
phpのautoloadとは、簡単に言うと、
名前空間を指定するだけで、自動的にファイル(クラス)名を解決してくれる仕組みのことだ。
// bootstrap/app.php
$app = new Illuminate\Foundation\Application(省略);
上記はLaravelのプロジェクトルート/bootstrap/app.phpに記載されている、オートロードが使用されている箇所の抜粋である。
インスタンスをnewする際に、クラス名ではなく名前空間(Illuminate\Foundation\Application)を指定しているのが分かる。
しかし実際にnewされているのは「プロジェクトルート/vender/laravel/framework/src/Illuminate/Foundation/Application.php」に記述されているクラスのインスタンスだ。
上記のように名前空間の指定で対応するクラス名を解決してくれるのがautoloadだ。
autoload(オートロード)のメリット
名前空間の指定で対応するクラス名を解決してくれることのメリットは、
いちいちnewしたいクラスが書かれたファイルをrequireしなくても良いことだ。
1ファイルとかならまだ良いが、たくさんのファイルが絡み合ってくると、その分だけrequireを記載しなければならなくなるため、大規模な開発になるほどrequireするのが大変になってくる。
だがautoloadを使用することで、使用したいクラスがある時は名前空間を指定するだけで良いため、上記の手間を省くことができる。
autoload(オートロード)の使い方
Laravelではプロジェクト作成後すでにautoloadの準備が整っているが、勉強として自分でautoloadをしてみた。その時の方法をメモ。
autoloadは以下の手順で使用可能となる。
- composer.jsonの準備
- (コマンド) composer install を実行
- 呼び出される側のファイルを作成、namespaceを指定する
- 呼び出す側のファイルを作成、/vender/autoload.phpをrequire
ポイントしては、autoloadはcomposerを使用すると言う点だ。
① composer.jsonの準備
まずはどこでも良いのでcomposer.jsonと言うファイルを以下の内容で作成する。
{
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
}
「App」のバリューを「app」としている部分が重要。
これで、namespaceの「App\」の部分は、ディレクトリ「app\」と対応するようになる。
ちなみにpsr-4と言うのが、ファイルパスからクラスを判別するautoloadの仕様について記載されているものだ。
② (コマンド) composer install を実行
composer.jsonを配置した階層で以下のコマンドを実行する
(※実行にはcomposerのインストールが必要)。
composer install
実行後、同階層に「composer.lock」と「vender」が作成される。
venderの下には「autoload.php」と言うファイルが存在する。
├── composer.json
├── composer.lock(作成される)
└── vendor(作成される)
└── autoload.php(作成される)
③呼び出される側のファイルを作成、namespaceを指定する
composer.jsonと同階層から、app/Test/Hello.php(呼び出される側のファイル)を作成する。
Hello.phpには以下のように記述する。
// app/Test/Hello.php
<?php
namespace App\Test;
class Hello{
function hello(){
echo "Hello World!";
}
}
namespaceに、「App\Test」と指定するのがポイント。
namespaceとディレクトリ構造は合わせる必要がある(Appはappと対応させたので、app/Testとなる)
③ 呼び出す側のファイルを作成、/vender/autoload.phpをrequire
composer.jsonと同階層に、「sample.php」と言うファイルを作成する。
そして冒頭でvender/autoload.phpをrequireする。その後、new App\Test\Hello();と言う名前空間でインスタンスをnewする。
// sample.php
<?php
require_once "vendor/autoload.php";
$hello = new App\Test\Hello();
echo $hello->hello();
vender/autoload.phpをrequireすることで、autoload(オートロード)が使用可能となる。
その後、名前空間でクラスをnewできるか確認するために、new App\Test\Hello();を挿入する。
ファイルを実行してautoloadされているか確認してみる
現在、以下のようなディレクトリ構造であること。
├── app(自分で作成)
│ └── Test(自分で作成)
│ └── Hello.php(自分で作成、呼び出される側のファイル)
├── composer.json
├── sample.php(自分で作成、呼び出す側のファイル)
└── vendor
└── autoload.php
以上でsample.phpを実行
> php sample.php
Hello World!
Hello World!と表示されたら、autoloadが機能している。
sample.phpから、app/Test/Hello.phpをrequireせずとも、
無事に、App\Test\Hello()と言う名前空間を使用してクラスを使用することができた。
今回は1ファイルで実行したが、もっと量が多くなると便利だろうと思う。
参考:(Laravel) namespaceとクラスの紐付け
参考までに、autoloadの仕組みは分かったけど、でも魔法が起きている訳ではないんだから、
どっかでnamespaceをクラス名と紐付けて解決しているようなファイルがあるはずと思い、Laravelのソースを読んでいると、あった。以下のファイルがLaravelでnamespaceとクラス名の紐付けを行っているファイルだ。
vender/composer/autoload_classmap.php
キーがnamespace、バリューがvenderディレクトリからの実体となるファイルパスの連想配列が記載されている、autoload_classmap.phpと言うファイルだ。
このファイルをvender/composer/autoload_real.phpで読み込んでおり、
namespaceからのクラス名解決は、vender/composer/ClassLoader.phpの、loadClass関数※で行っている。
※loadClass関数自体は、sql_auto_load関数に引数として設定されている、クラス解決のための救済メソッドだ。sql_auto_load関数を知っていないとこのへんは魔法にしか見えないと思うので、下記にsql_auto_load関数についてまとめた記事を紹介しておく。
気になる人は、上記を参考にソースを読んでみることをおすすめする。
https://www.php.net/manual/ja/language.oop5.autoload.php
https://www.php.net/manual/ja/function.spl-autoload-register.php
関連記事