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

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

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

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

[「psr-4 autoload 複数パス」とググって](https://www.google.com/search?q=psr-4+autoload+%E8%A4%87%E6%95%B0%E3%83%91%E3%82%B9)もタイトルからピンポイントで欲しい記事がヒットしなかったので、自分のググラビリティとして。

## TL;DR

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

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

> <sup>🐒 &nbsp; **JSON の `{ }`（波括弧、中括弧）と `[ ]`（角括弧、大括弧）の違いは、PHP の配列で言う「添字（キー）のあり・なし」で考えると楽**です。つまり、PHP でも添字（キー）を省略できるものが `[ ]` と言うことです。</sup>
> <sup>・ 数値の添字配列でキーが連番、もしくは省略して（自動連番でキーを割り当てて）いる場合は `[ ]`。</sup>
> <sup>・ キーが文字列もしくは数値でも連番ではない場合は `{ }` です。</sup>
>
> ```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}
> ```
>
> - [オンラインで動作をみる](https://paiza.io/projects/uPBIu-_cTi7Mt3UpkdwZoA) @ paiza.IO

## TS; DR

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

> If you need to search for a same prefix in multiple directories, you can specify them as an array as such:
> 
> ```json
> {
>     "autoload": {
>         "psr-4": { "Monolog\\": ["src/", "lib/"] }
>     }
> }
> ```
> 筆者訳）
> 複数んディレクトリで同じ名前空間プレフックスを検索すっ必要があっ場合は、以下んごつそれらを配列として指定できっ。
>
> <sup>（[PSR-4](https://getcomposer.org/doc/04-schema.md#psr-4) | Autoload | The Composer.json Schema | Documentation @ Composer 公式 より）</sup>

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

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

```diff:Diff
"psr-4": {
-    "MyApp\\": "src/classes/"
+    "MyApp\\": [
+        "src/classes/",
+        "src/classes/commands"
+    ]
}
```

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

### 所感

自作 PHP クラスを設置したディレクトリがあります（下図 `classes`）。

これらを [Composer のオートローダーを使いクラス・ファイルをいちいち `include` しなくても使える](https://qiita.com/tadsan/items/a78c9160418200e2d47a)ようにしました。

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

この２つのディレクトリ（`classes` と `classes/commands`）を、**同じ名前空間のクラスとして検索対象にしたい**のです。

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

うっすらと「（配列で指定するんだろうなぁ）」とは感じていたものの、[「`psr-4` `autoload` `複数パス`」でググって](https://www.google.com/search?q=psr-4+autoload+%E8%A4%87%E6%95%B0%E3%83%91%E3%82%B9)も、タイトルからピンポイントでわかる記事がありませんでした。

記事をひらけば、[名前空間が異なる場合の有用な情報](https://qiita.com/yotsak83/items/cc1a4936c0c92099db5a#3-composerjson%E3%81%AE%E4%BD%9C%E6%88%90)はあったものの、なかなか**同じ名前空間の場合の情報が見つからない**のです。

そこで、実際に配列で試してみたらアッサリ動いたのですが、Composer の公式ドキュメントを読んだら普通に[書いてありました](https://getcomposer.org/doc/04-schema.md#psr-4)。また忘れるであろう未来の自分のためのググラビリティとして残すことにしました。

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

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

- 「[include って書きたくない僕たちのためのオートローディングと Composer](https://qiita.com/tadsan/items/a78c9160418200e2d47a)」@ Qiita
- 「[PSR-4](https://getcomposer.org/doc/04-schema.md#psr-4)」| Autoload | Composer.json Schema @ Composer 公式
- 「[Symfony の console コンポーネントを使って CLI コマンドを作成する](https://qiita.com/YusukeHigaki/items/cc5729b772ec963de7c2)」@ Qiita
- 「[Console Commands](https://symfony.com/doc/current/console.html)」| v4 | Documentation @ Symfony 公式
- 「[PHP の PSR-0 と PSR-4 の autoloader の違い](https://qiita.com/KEINOS/items/2924ecde3e4bab0ead7e)」@ Qiita


### 検証環境

- 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