composer: Autoload optimizer violates PSR-4 and changes autoloading algorithm

When composer optimizes loading of files under PSR-4 root, it does not check correspondence between directory paths and namespaces. So if developer makes a mistake and puts php file in wrong directory, the application behaves differently when optimized and when not optimized.

I am not completely sure if we have to implement this. At first, this issue may be classified as “undefined behavior” and it isn’t Composer’s fault. Also it would be a breaking change for projects relying on this bug.
But It’s very productive when my tools help me to find errors on early stage, not hide them.

Composer version: 1.6.5

My directory layout:

src
|---BadDirectory
|   |---Example.php
composer.json
test.php

composer.json:

{
    "autoload": {
        "psr-4": {
            "and800\\Example\\": "src/"
        }
    }
}

Example.php:

<?php
namespace and800\Example;
class Example {}

test.php

<?php
include __DIR__ . '/vendor/autoload.php';
new and800\Example\Example();
echo "autoload succeed";

When I run this command:

$ composer install && php test.php
$ composer install -o && php test.php

I get the following output:

PHP Fatal error:  Uncaught Error: Class 'and800\Example\Example' not found in /tmp/ctest/test.php:3
autoload succeed

And I expected this to happen:

PHP Fatal error:  Uncaught Error: Class 'and800\Example\Example' not found in /tmp/ctest/test.php:3
PHP Fatal error:  Uncaught Error: Class 'and800\Example\Example' not found in /tmp/ctest/test.php:3

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 21 (16 by maintainers)

Most upvoted comments

I’d rather not have an additional flag for this. If we implement it I feel like it should be the default (and only) behavior. It definitely should be mentioned in the release notes as it’s a possible issue for people relying on the bug, but optimized autoloader really shouldn’t be used in development IMO and strictly speaking it’d be a bug fix so I wouldn’t say it’s a BC break.

In my case I ran into this because a project has optimization enabled in the composer.json. A colleague made classes with non-matching namespace and directory. This behaviour of composer was unknown to us, so we basically relied on Composer to know whether the FQCN was correct: if the autoloader finds it, it’s correct.

That turns out to be a false assumption now. Code could pass verification because of that assumption, where it should actually be rejected.

The build system, which ships the code to production, doesn’t use -o flag.

I would consider it a bug of the build system to be honest 😄 Production is precisely the place where you should be using optimized mode.

ignore any class that is not in its valid psr-0/4 path. Possibly with a warning to highlight the issue.

@Seldaek I think there must be no warning, othervise it will be triggered for every file that has more than one class inside, which is generally not bad 🤔

@alcohol -o means I want to optimize the autoloader. I would find it perfectly fine from Composer to enforce the PSR rules when building the classmap meant to optimize the PSR lookup. Currently, the implementation builds the classmap forgetting entirely it was meant to be a PSR structure (and so will happily register classes violating PSR and so not found in on-optimized mode).

actually I can implement a fix during next week