PHPのオートロードはrequireを使わず、use演算子を定義して自動的にクラスをロードする機能です。
オートロードはPHPパッケージを管理するcomposerの一部で、PHPではかならず必要な機能です。
その機能の中身、使い方をくわしく、かんたんに、分かるように説明します。
オートロードってなんぞや?
オートロードは、requireなしで、use演算子を定義するだけで、PHPのクラスを使えるようにする機能です。
<?php
require "TestClass1.php";
require "TestClass2.php";
require "TestClass3.php";
use TestClass1;
use TestClass2;
use TestClass3;
$test1 = new TestClass1();
$test2 = new TestClass2();
$test3 = new TestClass3();
<?php
require vendor/autoload.php
use TestClass1;
use TestClass2;
use TestClass3;
$test1 = new TestClass1();
$test2 = new TestClass2();
$test3 = new TestClass3();
どこにもTestClass*を書いてないのに、TestClass*.phpを取り込んでいないのにエラーになりません。
TestClassはすでにオートロードがrequireしてくれたからです。
オブジェクト指向プログラミングでは大量のクラスを使います。そして、クラスは『1ファイル1クラス』というルールがあります。
オートロードがなければ、大量のrequireを書かないといけません。それをしないためにオートロードがあります。
autoloadを使ってみよう!
くわしい説明をする前にautoloadを使ってみましょう。
同じように作業するだけでいいです。
まず、composerがないと使えません。composerをPHP環境にインストールします。
composer.jsonファイルの作成
PHPのプロジェクトホームへ移動します。
ここでは、user-test/php-test-autoloadです。
...─ php-test-autoload
├─(空)
まだ、プロジェクトの中身は空っぽです。
ここでcomposerのコマンドを実行します。
composer init
いろいろな入力を求められますが、とりあえず、ぜんぶ Enter でいいです。
...─ php-test-autoload
├─ composer.json
プロジェクトのホームにcomposer.jsonができました。
{
"name": "user-test/php-test-autoload",
"authors": [
{
"name": "user-test",
"email": "user-test@gmail.com"
}
],
"require": {}
}
authorsが空っぽでもいいです。これは、php.iniで設定していないと追加されません。
autoloadパッケージのインストール
プロジェクトにはcomposer.jsonしかありません。
つぎに、autoloadのパッケージをインストールします。
composer install
autoloadパッケージがインストールされました。
...─ php-test-autoload
├─ vendor
│ ├─ composer
│ │ ├─ autoload_classmap.php
│ │ ├─ autoload_namespaces.php
│ │ ├─ autoload_psr4.php
│ │ ├─ autoload_real.php
│ │ ├─ autoload_static.php
│ │ ├─ ClassLoader.php
│ │ ├─ installed.php
│ │ └─ LICENSE
│ └─ autoload.php
└─ composer.json
vendorディレクトリは、composer.jsonのrequireに追加するパッケージのインストール先です。
autoloadはcomposerの機能なので、vendor/composerディレクトリにインストールされました。
vendor/autoload.php
もありますね?
これをrequireするだけでオートロードすることができます。
autoloadはcomposerの基本機能なので、1回目のcomposer installコマンドで必ずインストールされます。
composer.jsonのrequireが空っぽでも同じ。
(compsoer.jsonのrequireはプロジェクトにインストールするパッケージリストです。)
PHPのサンプルプログラム作成
autoloadのパッケージがプロジェクトに追加されました。
こんどは、プロジェクトにサンプルプログラムを追加します。
...─ php-test-autoload
├─ src
│ ├─ main.php
│ ├─ TestClass1.php
│ ├─ Test2
│ │ └─ TestClass2.php
│ └─ Test3
│ └─ TestClass3.php
├─ vendor
│ ├─ composer
│ │ ├─ autoload_classmap.php
│ │ ├─ autoload_namespaces.php
│ │ ├─ autoload_psr4.php
│ │ ├─ autoload_real.php
│ │ ├─ autoload_static.php
│ │ ├─ ClassLoader.php
│ │ ├─ installed.php
│ │ └─ LICENSE
│ └─ autoload.php
└─ composer.json
<?php
namespace Origin;
class TestClass1 {
function __construct() {
echo "new instance TestClass1\n";
}
}
<?php
namespace Origin\Test2;
class TestClass2 {
function __construct() {
echo "new instance TestClass2\n";
}
}
TestClass3も同じようにします。
TestClass1とTestClass2, TestClass3のnamespaceがちがうところに注意。
あとで出てきますが、今回はpsr4というコーディング規約を使います。psr4では、
- クラスファイルはnamespaceが必須。
- namespaceとディレクトリ構成、名称は一致させる。
- namespace名は大文字からはじめる。
のルールがあります。
PSR (PHP Standards Recommendations)
PHP標準勧告。PHPコーディングの標準化を目指す活動のこと。PHP-FIGが策定している。
PHP-FIG (PHP Framework Interop Group)
PHPフレームワーク相互運用グループ。PHPプロジェクトが集まって意見を出し合い、お互いの製品の互換性を調整する団体。
有名なプロジェクトが多く参加している。
<?php
require "vendor/autoload.php";
use Origin\TestClass1;
use Origin\Test2\TestClass2;
use Origin\Test3\TestClass3;
new TestClass1();
new TestClass2();
new TestClass3();
composer.jsonの編集
クラスファイルがあるディレクトリを、autoloadが取り込めるように登録します。
登録は、composerの設定ファイル、composer.jsonでおこないます。
{
"name": "user-test/php-test-autoload",
"authors": [
{
"name": "user-test",
"email": "user-test@gmail.com"
}
],
"require": {},
"autoload": {
"psr-4": {
"Origin\\": "src/"
}
}
}
autoload{}で、srcディレクトリにあるクラスファイルはOriginからはじまるように登録しています。
psr4では、namespace名は大文字からはじめなければならないので、srcは使えません。
ここでは、クラスをロードするときにsrcをOriginに変換してnamespaceと一致させます。
ディレクトリ構成とネームスペース構成を一致させる
composerを使ってパッケージをインストールしたときにcomposer.jsonが更新されます。
パッケージのクラスは自動的にautoload{}に追加されます。自分で作業する必要はありません。
今回は、自作のプログラムでcomposerのパッケージではないので直接編集しました。
composer.jsonを直接編集したときは
composer validate
コマンドを必ず実行します。
これは、composer.jsonの構文チェックコマンドです。
エラーが出ると編集したところがまちがっています。
composerコマンドが使えなくなるので気をつけましょう。
autoloadのマップファイル更新
autoloadを更新します。
composer update
正確には、composer.jsonの設定を更新します。autoload{}を追加したので、autoloadも更新します。
autoloadの仕組みはかんたん。
composer install
composer update
composer require
のコマンドを実行すると、マップファイルを作成・更新します。
マップファイルの中身はただの配列で、クラスやネームスペースが定義されています。
オートロードってクラスをロードしているんじゃなくて定義されたクラスを参照しているだけなんですね?
...─ php-test-autoload
└─ vendor
└─ composer
├─ autoload_classmap.php
├─ autoload_namespaces.php
├─ autoload_psr4.php
├─ autoload_static.php
└─ installed.php
さっきみた、autoloadのこれらのファイルがマップファイルです。
composer.jsonで、psr4のautoload登録をしたので、
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Origin\\' => array($baseDir . '/src'),
);
こんなかんじで更新されます。
きちんとsrc -> Originの変換がマップに登録されてます。
composerコマンドでcomposer.jsonファイルを更新すると、autoload{}で定義した内容をautoloadのマップファイルに展開する。
vendor/autoload.phpは、すべてのマップファイルのまとめ役です。
だから唯一requireします。
プログラムを実行してみよう!
autoloadのサンプルプログラムが完成しました。これを実行してみましょう。
php src/main.php
new instance TestClass1
new instance TestClass2
new instance TestClass3
プロジェクトのホームで実行して同じ結果が出たら、autoloadの使い方はバッチリです。
autoloadマップの更新
さっきは、
composer update
でマップファイルを更新しました。
でもこのコマンドは、composer.jsonファイルの更新に使うもので、マップの更新につかうものではありません。
たとえば、ソースコードを追加したときのクラスはマップに登録されていません。
composer.jsonを編集していないので"composer update"コマンドも使えません。
そのときは、
composer dump-autoload
をつかいます。
これは、autoloadのマップだけを再構築します。
Class not Found
が発生したら実行しましょう。
意外と、プログラムのバグではなくマップが更新されてないだけのときがあります。
dump-autoload -o を使うときは要注意!
composer dump-autoload -o
autoloadには、
Autoloader Optimization
という高速に読み込むためのマップの最適化機能があります。
オプション-oをつけます。しかし注意が必要です。
このオプションをつけると、クラスマップを再構築するときpsr-4のルールを無視します。
psr-4に準拠しないnamespaceとディレクトリ構成のクラスファイルもクラスマップに登録されます。
とつぜん、
Class not Found
が出まくるときもあります。
オプションをつけてマップ更新していて、あるときオプションをつけずに更新したときに起きます。
意外とこのパターンは多いです。
Laravelではよく起きる現象なので注意が必要です。
開発環境はオプションなし
本番環境はオプションあり
という使い方をしたほうがいいでしょう。
クラス以外もオートロードできる
autoloadはクラス以外でもオートロードできます。
- インタフェース
- function
- const
<?php
require vendor/autoload.php;
use My\Full\ClassName as ClassName;
use My\Full\InterfaceName as IFName;
class Test extends ClassName implements IFName {
// ...
}
// >= PHP 5.6
use function My\Full\functionName as func;
$ret = func();
// >= PHP 5.6
use const My\Full\CONSTANT CONST_A;
$val = CONST_A;
ただし、function, constはPHPのバージョンが5.6以降でないと対応していません。
Laravelにはすでに入っている
PHPのWebフレームワーク、Laravelにはcomposerが入っています。
composer.jsonもありますし、vendor/composerにはautoloadのパッケージもあります。
require vendor/autoload.php
も必要ありません。
すでに、public/index.phpに実装されています。
autoloadのまとめ
- "require vendor/autoload.php"をソースコードに1回だけ書く。
- use演算子でクラス、インタフェース、function、constがオートロードできる。
- 設定はcomposer.json
autoloadの基本的な使い方はこれだけです。
『ここで終わり』と行きたいところですが、ちょっと上級編をつづけます。
composer.jsonのautoload{}でつかったpsr4の説明もしていませんでしたね?
そのほかの指定方法も解説します。
autoloadで指定する種類
composer.jsonのautoload{}は、psr-4以外にもいろいろな指定方法があります。
ひとつひとつ見ていきましょう。
files
"autoload": {
"files": [
"src/functions/func1.php",
"src/const/const1.php",
]
}
.phpファイルからfunctionやconstをオートロードします。
クラスやインタフェース以外のときに使います。
マップファイル
vendor/composer/autoload_files.php
psr-4
"autoload": {
"psr-4": { "Vendor\\": "src/vendor/" }
}
"autoload": {
"psr-4": { "Vendor\\": ["src/Vendor/", "lib/Vendor/"] }
}
Laravelなど、psrに準拠したものに使います。
psr-4はネームスペースとディレクトリ構成は一致させます。
そのトップレベルのネームスペースのディレクトリの位置を指定します。
[]で括って複数指定することもできます。
PHPではPSRに準拠することがふつうで、WordPressのように参加していないほうが珍しいです。
(といっても参加していないプロジェクトは多いが。)
psr-4でネームスペースとディレクトリ構成が一致しないとき、アプリケーション実行時に
Class not Found
が発生します。
パッケージ自体のエラーは発生しないので、あたかもアプリケーションにバグがあるかのように見えます。
autoloadのマップ情報が古いか、パッケージのバグの可能性があります。
psr-4には、psr-0で設定する内容も含まれます。
あとで説明するpsr-0の設定はいりません。
マップファイル
vendor/composer/autoload_psr-4.php
vendor/composer/autoload_static.php
vendor/composer/autoload_classmap.php
psr-0
"autoload": {
"psr-0": {
"Vendor\\": "src/Vendor/",
"Vendor\\Namespace\\": "src/Vendor/",
"Vendor_Namespace_": "src/"
}
}
いまのpsrのレベルは4が主流です。
レベルが大きいpsrはそれ以下のレベルも含むのでpsr-0はほとんど使うことはありません。
数年前からつづいてきたプロジェクトなど、古いソースコードや、psr-2まで準拠しているもので使います。
composerのautoloadにはpsr-2はありません。
マップファイル
vendor/composer/autoload_classmap.php
classmap
"autoload": {
"classmap": ["src/", "lib/", "Something.php"]
}
WordPressなど、psrに準拠しないときに使います。
マップファイル
vendor/composer/autoload_classmap.php
exclude-from-classmap
"autoload": {
"exclude-from-classmap": ["/Tests/", "/test/", "/tests/"]
}
autoloadの除外設定をします。
テストクラスなど本番環境では使わないクラスを指定します。
マップファイル
vendor/composer/autoload_classmap.php
開発環境のautoload
開発環境のautoloadを設定します。
テストクラスなどを指定し、指定できるディレクトリはルートディレクトリだけです。