PHP Composer の autoload で同じ名前空間で複数パスを定義する(PSR-4)


composer のオートローダー利用時の PSR-4 検索パスを複数指定したい。

問題のcomposer.json
{
    "autoload": {
        "psr-4": {
            "MyApp\\": "src/"
        }
    }
}

上記の "MyApp\\": "src/" で、他のディレクトリ/フォルダも検索の対象にしたいのです。

「psr-4 autoload 複数パス」とググってもタイトルからピンポイントで欲しい記事がヒットしなかったので、自分のググラビリティとして。

TL;DR

名前空間と検索ディレクトリのマッピングは配列で指定可能

composer.json
{
    "autoload": {
        "psr-4": {
            "MyApp\\": [
                "src/",
                "lib/classes/"
            ]
        }
    }
}

🐒   JSON の { }(波括弧、中括弧)と [ ](角括弧、大括弧)の違いは、PHP の配列で言う「添字(キー)のあり・なし」で考えると楽です。つまり、PHP でも添字(キー)を省略できるものが [ ] と言うことです。
・ 数値の添字配列でキーが連番、もしくは省略して(自動連番でキーを割り当てて)いる場合は [ ]
・ キーが文字列もしくは数値でも連番ではない場合は { } です。

echo json_encode([ 'a','b','c' ]);
// ["a","b","c"]
echo json_encode([ 0=>'a', 1=>'b', 2=>'c']);
// ["a","b","c"]
echo json_encode([ 0=>'a', 10=>'b', 20=>'c']);
// {"0": "a","10": "b","20": "c"}
echo json_encode([ 'a'=>1, 'b'=>2, 'c'=>3 ]);
// {"a":1,"b":2,"c":3}

TS; DR

なんか公式ドキュメントに書かれてました。。。

If you need to search for a same prefix in multiple directories, you can specify them as an array as such:

{
    "autoload": {
        "psr-4": { "Monolog\\": ["src/", "lib/"] }
    }
}

筆者訳)
複数んディレクトリで同じ名前空間プレフックスを検索すっ必要があっ場合は、以下んごつそれらを配列として指定できっ。

PSR-4 | Autoload | The Composer.json Schema | Documentation @ Composer 公式 より)

つまり、日本語で言うと「"composer.json" の "psr-4" の名前空間の要素は配列でも定義できるよ」ということです。

以下は、サブディレクトリも検索対象にする例です。

Diff
"psr-4": {
-    "MyApp\\": "src/classes/"
+    "MyApp\\": [
+        "src/classes/",
+        "src/classes/commands"
+    ]
}
before
{
    ...
    "autoload": {
        "psr-4": {
            "MyApp\\": "src/classes/"
        }
    },
    ...
}
after
{
    ...
    "autoload": {
        "psr-4": {
            "MyApp\\": [
                "src/classes/",
                "src/classes/commands"
            ]
        }
    },
    ...
}

所感

自作 PHP クラスを設置したディレクトリがあります(下図 classes)。これらを Composer のオートローダーを使いクラス・ファイルをいちいち include しなくても使えるようにしました。

その後、クラス・ファイルが増えたので用途ごとに整理するためディレクトリを掘り下げました(下図 commands)。しかし、いずれのクラス名も同じ名前空間を持っています。

この2つのディレクトリ(classesclasses/commands)を、同じ名前空間のクラスとして検索対象にしたいのです。

基本構成
.
├── composer.json
├── src
│   ├── index.php
│   └── classes ← この階層のパスと
│       ├── Item.php
│       └── commands ← この階層のパスを対象にしたい
│           ├── AddItemCommand.php
│           └── MoveItemCommand.php
└── vendor
    ├── autoload.php
    ├── composer
    │  (省略)
    └── symfony
        ├── console
       (省略)

うっすらと「(配列で指定するんだろうなぁ)」とは感じていたものの、psr-4 autoload 複数パス」でググっても、タイトルからピンポイントでわかる記事がありませんでした。

記事をひらけば、名前空間が異なる場合の有用な情報はあったものの、なかなか同じ名前空間の場合の情報が見つからないのです。そこで、実際に配列で試してみたらアッサリ動いたのですが、Composer の公式ドキュメントを読んだら普通に書いてありました。また忘れるであろう未来の自分のためのググラビリティとして残すことにしました。

composer.json全文
{
    "name": "keinos/myapp",
    "description": "Sample project.",
    "type": "project",
    "license": "Apache License 2.0",
    "authors": [
        {
            "name": "MyName",
            "email": "[email protected]"
        }
    ],
    "autoload": {
        "psr-4": {
            "MyApp\\": [
                "src/classes/",
                "src/classes/commands"
            ]
        }
    },
    "require": {
        "symfony/console": "^4.2"
    }
}

参考文献&あわせて読みたい

検証環境

  • macOS Mojave(OSX 10.14.3)
  • PHP v7.1.23 (cli) (built: Nov 7 2018 18:20:35) ( NTS )
  • Composer v1.8.4 2019-02-11 10:52:10