Fix UniversalClassLoader matching collisions. #43

Closed
wants to merge 1 commit into
from

Projects

None yet

3 participants

@bobthecow

The current loadClass() implementation tries to load a class from the first matching prefix or namespace then stops, producing false-negative results. This is especially evident in groups of related libraries, such as Doctrine:

Doctrine
Doctrine\Common
Doctrine\Common\DataFixtures
Doctrine\DBAL
Doctrine\DBAL\Migrations

Each of these libraries is submoduled into a different vendor directory. Classes may or may not actually be loaded depending on what order these libraries are added to a UniversalClassLoader instance. This fix continues searching registered namespaces and prefixes if the first partial match is negative.

@bobthecow bobthecow Fix UniversalClassLoader matching collisions.
The current `loadClass()` implementation tries to load a class from the first matching prefix then stops, producing false-negative results. This is especially evident in groups of related libraries, such as Doctrine:

    Doctrine
    Doctrine\Common
    Doctrine\Common\DataFixtures
    Doctrine\DBAL
    Doctrine\DBAL\Migrations

Each of these libraries is submoduled into a different vendor directory. Depending on what order these libraries are added to a UniversalClassLoader instance, classes may or may not actually be loaded. This fix continues searching registered namespaces and prefixes if the first partial match is negative.
54d20f2
@fabpot
Member
fabpot commented Jan 4, 2011

Orders matter, and I think this is a good thing. You must put the most precise namespace first. I don't want the autoloader to be able to load the same class from different directories as it can become a nightmare pretty fast. Or is there another reason?

@chesteroni

If there is another reason (than putting namespaces in random order), maybe a solution is as follows: current behaviour remain unchanged, but when in configuration appears a proper setting, the loader look at all directories?
e.g.
classloader_search_directories = true/false [default=false]

@fabpot
Member
fabpot commented Jan 4, 2011

Why make things more complicated?

@bobthecow

This isn't about putting namespaces in a random order. It's about keeping UniversalClassLoader from doing anything unexpected. In Symfony2 configs, anything set later will overload earlier values. By this precedent, I would expect the following to work:

$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
    'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib',
    'Doctrine\\DBAL'   => __DIR__.'/vendor/doctrine-dbal/lib',
    'Zend'             => __DIR__.'/vendor/zend/library',
));
$loader->registerNamespaces(array(
    'Doctrine\\Common\\DataFixtures' => __DIR__.'/vendor/doctrine-data-fixtures/lib',
    'Doctrine\\DBAL\\Migrations'     => __DIR__.'/vendor/doctrine-migrations/lib',
));
$loader->register();

But of course it doesn't, because the set of namespaces registered earlier include two collisions. Surprisingly, the following won't work either:

$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
    'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib',
    'Doctrine\\DBAL'   => __DIR__.'/vendor/doctrine-dbal/lib',
    'Zend'             => __DIR__.'/vendor/zend/library',
));
$loader->registerNamespaces(array(
    'Doctrine\\Common\\DataFixtures' => __DIR__.'/vendor/doctrine-data-fixtures/lib',
    'Doctrine\\Common'               => __DIR__.'/vendor/doctrine-common/lib',
    'Doctrine\\DBAL\\Migrations'     => __DIR__.'/vendor/doctrine-migrations/lib',
    'Doctrine\\DBAL'                 => __DIR__.'/vendor/doctrine-dbal/lib',
));
$loader->register();

But this works just fine:

$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
    'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib',
    'Doctrine\\DBAL'   => __DIR__.'/vendor/doctrine-dbal/lib',
    'Zend'             => __DIR__.'/vendor/zend/library',
));
$loader->register();

$loader2 = new UniversalClassLoader();
$loader2->registerNamespaces(array(
    'Doctrine\\Common\\DataFixtures' => __DIR__.'/vendor/doctrine-data-fixtures/lib',
    'Doctrine\\Common'               => __DIR__.'/vendor/doctrine-common/lib',
    'Doctrine\\DBAL\\Migrations'     => __DIR__.'/vendor/doctrine-migrations/lib',
    'Doctrine\\DBAL'                 => __DIR__.'/vendor/doctrine-dbal/lib',
));
$loader2->register();

I'm not sure I understand your concern. This fix seems to be a net win. If you maintain the current "most precise first" namespaces, this will not be any slower or more complicated: it will return matches just as fast, and will never enter the fallback checks.

@fabpot
Member
fabpot commented Jan 6, 2011

merged.

@bobthecow

Thanks!

@SofHad SofHad pushed a commit to SofHad/symfony that referenced this pull request Oct 12, 2015
@javiereguiluz javiereguiluz bug #43 Fixed backend design for the listing actions (javiereguiluz)
This PR was merged into the master branch.

Discussion
----------

Fixed backend design for the listing actions

I was playing with the Russian translation kindly provided by @bocharsky-bw and I noticed the following issue:

![before](https://cloud.githubusercontent.com/assets/73419/7233447/8180a7a2-e781-11e4-939f-b8321c14245d.png)

After this PR, the actions should always be correctly displayed:

![after](https://cloud.githubusercontent.com/assets/73419/7233456/8a47b934-e781-11e4-8a42-29a4b172da43.png)

Commits
-------

bd6a4a6 Fixed backend design for the listing actions
59a686e
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment