💡

phpのautoloadを理解する

2024/01/02に公開

オートロードとは何か

phpのオートロードとは、未定義のクラスを呼び出した時に、クラスの定義を読み込む仕組みのことです。

オブジェクト指向プログラミングではクラスを定義するときにファイルを分割することが一般的です。例えば、Userクラスを定義するときに、User.phpというファイルを作成し、その中にUserクラスを定義します。

このとき、他のファイルでUserクラスを使いたい場合には、通常User.phpを読み込む必要があります。phpでは、require_onceなどといった関数を使ってファイルを読み込むことができます。

しかし、読み込むクラスが多くなると、ファイルの先頭にたくさんのrequire_onceを書く必要があり、コードが読みにくくなります。

そこで、phpでは、未定義のクラスを呼び出した時に、クラスの定義を読み込む用途で指定した処理をさせることができる仕組みが用意されています。これがオートロードです。

オードロードの仕組み

spl_autoload_register

オートロードの時の挙動は、spl_autoload_register関数を使って定義します。

spl_autoload_register関数は、引数にコールバック関数を取ります。ここで指定したコールバック関数が、未定義のクラスを呼び出した時に実行されます。

コールバック関数の引数には、呼び出されたクラス名(string/文字列型)が入ります。コールバック関数の中で、クラス名に対応するファイルを読み込む処理を書きます。

spl_autoload_register(function ($class) { // $classには呼び出されたクラス名が入る
    // クラスを定義するファイルを読み込む処理
});

コード例

コード例を用いて、autoloadの挙動を確認します。
ファイルを分けない場合、autoloadを使わない場合、autoloadを使う場合の3つの例を示します。

以下の例では全てのファイルを同じディレクトリに配置してください。

ファイルを分けない場合

index.php
<?php

class User
{
    public function __construct()
    {
        echo 'Userクラスのインスタンスが生成されました。' . PHP_EOL;
    }
}

$user = new User();

実行結果

</>terminal
$ php index.php
Userクラスのインスタンスが生成されました。

autoloadを使わない場合

index.php
<?php
require_once 'user.php';

$user = new User();

User.php
<?php
class User
{
    public function __construct()
    {
        echo 'Userクラスのインスタンスが生成されました。' . PHP_EOL;
    }
}

実行結果

</>terminal
$ php index.php
Userクラスのインスタンスが生成されました。

autoloadを使う場合

以下は、autoloadを使った場合の例です。autoload.phpというファイルで、autoloadの挙動を定義して、index.phpでautoload.phpを読み込んでいます。

autoload.php
<?php
spl_autoload_register(function ($class) {
    echo '1. ' . $class . 'クラスを読み込みます。' . PHP_EOL;
    require_once $class . '.php';
    echo '2. ' . $class . 'クラスを読み込みました。' . PHP_EOL;
});

User.php
<?php
class User
{
    public function __construct()
    {
        echo 'Userクラスのインスタンスが生成されました。' . PHP_EOL;
    }
}

index.php
<?php
require_once 'autoload.php';
// require_once 'user.php';

$user = new User(); // 明示的にuser.phpを読み込む必要がなくなった

実行結果

</>terminal
$ php index.php
1. Userクラスを読み込みます。
2. Userクラスを読み込みました。
Userクラスのインスタンスが生成されました。

オートロードの規約

オートロードを使う時のルールとしては、PHP-FIGが作成したPSR-4という規約がデファクトスタンダードとなっています。

https://www.php-fig.org/psr/psr-4/

PSR-4

以下の記事でPSR-4の内容を翻訳しています。
https://zenn.dev/aki_artisan/articles/psr4-translation-ja

短く説明すると、PSR-4では、名前空間とディレクトリを対応させておき、それ以下のサブ名前空間をディレクトリで、クラス名をファイル名でそれぞれ対応させるという仕様です。

例えば、App\SomeModule\SomeUnitというクラスをsrc/から読み込ませたい場合、Appという名前空間をsrcディレクトリに対応させれば、App\SomeModule\SomeUnitsrc/SomeModule/SomeUnit.phpから読み込まれるようになります。

名前空間付きクラス名 名前空間接頭辞 ベースディレクトリ ファイルパス
\App\SomeModule\SomeUnit App ./src/ ./src/SomeModule/SomeUnit.php

Composerを使って実際のプロジェクトでautoloadを使う方法

簡単にautoloadを使うための方法の一つはComposerを使うことです。

Composerは、パッケージの依存関係を管理するためのツールで、標準でautoloadの実装を持っています。Composerのインストール方法は他の記事を参照してください。

https://getcomposer.org/

以下では、カレントディレクトリでComposerを使えることを前提としています。(検証環境はComposer version 2.5.8を使っています)

ディレクトリ構成は以下のようになっているものとします。/srcディレクトリと/publicディレクトリがあり、publicディレクトリの中にindex.phpがあります。

.
├── public
│   └── index.php
└── src

composer.jsonの作成

Composerを使うために、ディレクトリ直下にcomposer.jsonというファイルを作成します。

composer.json
{}
</>terminal
$ composer install

空のcomposer.jsonを作成した後、composer installコマンドを実行します。

すると、vendorディレクトリとcomposer.lockファイルが作成されます。autoload.phpはvendorディレクトリの中にあります。

.
├── composer.json
├── composer.lock
├── public
│   └── index.php
├── src
└── vendor
    ├── autoload.php
    └── composer

以下の例では、Appという名前空間をsrcディレクトリに対応させます。

index.phpでautoload.phpを読み込む

index.phpでautoload.phpを読み込みます。

index.php
<?php
require_once __DIR__ . '/../vendor/autoload.php';

$app = new App\MyApp();
$app->run();

クラスを定義する

読み込むためのクラスを定義します。

src/MyApp.php
<?php
namespace App;

class MyApp
{
    public function run()
    {
        echo 'Hello, world!' . PHP_EOL;
    }
}

composer.jsonにautoloadの設定を記述する

composer.jsonにautoloadの設定を記述します。

composer.json
{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

composer dump-autoloadを実行する

composer.jsonを変更した場合は、composer dump-autoloadコマンドを実行する必要があります。

</>terminal
$ composer dump-autoload

実行結果

実行してみると、正常にsrc/MyApp.phpが読み込まれていることがわかります。(クラスのrunメソッドが実行されている)

</>terminal
$ php public/index.php
Hello, world!

このようにして、PSR-4の規約に従ってクラスを読み込むことができました。

Composerのautoloadの仕様

PSR-4で複数のディレクトリに対応させる場合

composer.json
{
    "autoload": {
        "psr-4": {
            "App\\": ["src/", "app/"]
        }
    }
}

上記のように、複数のディレクトリに対応づけることができます。
そうした場合、左側にあるディレクトリから順に探索されます。そのため、両方のディレクトリに呼び出すクラスのファイルがある場合は、左側のディレクトリのファイルが読み込まれます。

まとめ

  • オートロードとは、未定義のクラスを呼び出した時に、ファイルからクラスの定義を読み込む仕組みのことです。
  • オートロードのための規約として、PSR-4がデファクトスタンダードとなっています。
  • Composerを用いてPSR-4にしたがったautoloadを使うことができます。

参考文献

https://www.php.net/manual/ja/language.oop5.autoload.php
https://www.php-fig.org/psr/psr-4/
https://getcomposer.org/doc/04-schema.md#autoload

GitHubで編集を提案

Discussion