One PSR-4 namespace can map to several directories

A namespace is usually written as if it maps to exactly one directory, and Composer accepts an array of them instead. That turns out to be the thing that makes a PSR-0 to PSR-4 migration incremental rather than a single commit that moves four hundred files.

{
    "autoload": {
        "psr-4": {
            "App\": [ "src/", "legacy/src/" ],
            "App\Reporting\": "modules/reporting/src/"
        }
    }
}

Directories under one prefix are searched in the order listed, first hit wins, so moving a class from legacy/src/ into src/ takes effect with no change to composer.json and no change to the class. The second entry shows the other rule worth knowing: Composer tries the longest matching prefix first, so AppReportingSummary is looked for under modules/reporting/src/ before the shorter App mapping is considered — which is how a submodule lives in its own tree without a namespace of its own. The cost is one stat per directory per miss, so a class that does not exist is now several failed lookups rather than one. dump-autoload --optimize collapses all of it into a classmap for production.