Drupal 7 の .info ファイルの files[] とは

今回は Drupal 7 の .info ファイルの files[] についてのお話です( Drupal に興味のない方にはおもしろくないちょっとマニアックなお話です・・・)。

Drupal で開発を行う際に必ず必要となるもののひとつが .info ファイルです。 その中に記述可能な項目のひとつに files[] というものがあります。

例えば Entity モジュールの .info ファイルは以下のような内容になっています(一部抜粋)。

name = Entity API
description = Enables modules to work with any entity type and to provide entities.
core = 7.x
(略)
files[] = entity.rules.inc
files[] = entity.test
files[] = includes/entity.inc
files[] = includes/entity.controller.inc
files[] = includes/entity.ui.inc
files[] = includes/entity.wrapper.inc
(略)

この files[] とは一体何なのか、なのですが、 一言でいうとこれは「 動的に読み込みたい PHP ファイルを指定できる機能 」、いわゆるオートローダ設定です。 PHP ファイルを files[] で指定しておくことで、 Drupal が必要なときにそのファイルを読み込んでくれるようになります。

かんたんにまとめると以下のような感じになるでしょうか。

  • files[] には files[] = ファイルパス という形で PHP ファイルを指定できる。
  • files[] で指定されたファイルは通常のブートストラップ処理では原則読み込まれない。
  • files[] で指定されたファイルは、その中で宣言されたクラスやインタフェースが初めて利用されたときに自動的に読み込まれる。
  • ただし、自動読み込みの対象は、クラス、インタフェース、トレイトのみ。関数は対象外。

ですので、例えば次の場合。

files[] = entity.test

この entity.test というのは Simpletest のテストクラスを格納したファイルです。 これはテストを実行するときにのみ必要で、それ以外のときには原則不要なものです。 files[] で宣言することによって、テスト実行時の必要なタイミングにのみ entity.test ファイルを Drupal が読み込んでくれるようになります。

この files[] のメリットは(いわずもがなですが・・・)以下のとおりです。

  • すべてのコードを .module 内に書くのではなく適切に files[] に分けることによって、メモリ使用量を減らすことができる(省メモリ化/パフォーマンス向上)
  • 適切にファイルを分けることによりコードの見通しをよくすることができる(開発効率向上)

上でちらっと述べましたが、これは一般にいう「オートローダ」と呼ばれる仕組みです。 PHP でオートローダといえば一般には PSR-0 や PSR-4 と呼ばれるローディングルールが有名です。

私は詳しくはありませんが、どうも PHP 自体がオートローダの API を用意しているそうで、 spl_autoload_register() という関数を使えば開発者が好きなようにオートローディング機構を構築できるようになっています。 Drupal 7 もこれを利用する形で独自のオートローダエンジンを作っています。

    /**
     * Initializes the database system and registers autoload functions.
     */
    function _drupal_bootstrap_database() {
      // (略)

      // Register autoload functions so that we can access classes and interfaces.
      // The database autoload routine comes first so that we can load the database
      // system without hitting the database. That is especially important during
      // the install or upgrade process.
      spl_autoload_register('drupal_autoload_class');
      spl_autoload_register('drupal_autoload_interface');
      if (version_compare(PHP_VERSION, '5.4') >= 0) {
        spl_autoload_register('drupal_autoload_trait');
      }
    }

PHP でいうオートローダというのは要は「クラス」と「読み込むファイル」の関係を定義することで、例えば PSR-0 や PSR-4 の場合(つまり Drupal 8 の場合)これは「クラスの FQCN とファイル構造」の関係に規約を設ける形で実現されています。

他方、 Drupal 7 の場合は独自の「 registry 」という仕組みでこれを実現しています。

具体的には、モジュールが有効化されたときに Drupal が files[] で宣言されているファイルをすべてスキャンし、その中からクラス/インタフェース/トレイトの宣言部分をすべて抽出し、「クラス」「インタフェース」「トレイト」と「クラスが所属するファイル」の関係をデータベースの registry テーブルに登録しておきます。 そして、ブラウザからのリクエストの処理中に各クラスが必要になったら、この registry テーブルを検索して対応するファイルを即座に読みにいく、という形になっています。

以上です。

手短でしたが Drupal 7 の files[] のプチ解説でした。

興味のある方は _registry_update()_drupal_bootstrap_database() の中身をご覧になってみてください。 よくできています。

最後に、 drupal.org の .info ファイルの解説ページの files[] の箇所を翻訳して終わりにしたいと思います。

files (Optional)

Drupal supports a dynamic-loading code registry. To support it, all modules must declare any code files containing class or interface declarations in the .info file, like so:

name = Really Neat Widget
...
files[] = tests/example.test

When a module is enabled, Drupal will rescan all declared files and index all the classes and interfaces that it finds. Classes will be loaded automatically by PHP when they are first accessed.

翻訳:

files (オプション)

Drupal は動的読み込みのコードレジストリをサポートしています。 これを実現するため、モジュールはクラスやインタフェースを含むファイルを .info ファイルで宣言する必要があります。 例は次のとおりです。

name = Really Neat Widget
...
files[] = tests/example.test

モジュールが有効化されたときに Drupal は宣言されたファイルをすべて再スキャンし、見つかったすべてのクラスとインタフェースのインデックスを作ります。 クラスは初めてアクセスされたときに PHP によって自動的に読み込まれます。