Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fix bug in classExists when using multiple autoloaders (i.e. ZF2) #184

Closed
wants to merge 3 commits into from

6 participants

@bramstroker

The autoloading routine in the classExists method makes the assumption the autoload method always returns a value (i.e. no void) when the autoloading of a class is succesfull. When you have multiple autoloaders registered to the spl stack this can lead to problems. In my case I'm using ZF2 ClassmapAutoloader and StandardAutoloader as fallback. The classmapAutoloader returns nothing so the autoload method in the StandardAutoloader is called as well, because the for loop is continued. This results in a second include, and a fatal error "Cannot redeclare class" is triggered.

@schmittjoh
Collaborator

Loaders that you pass to the AnnotationRegistry must return a boolean.

However, you can easily wrap the Zend autoloader instead of passing it directly:

AnnotationRegistry::registerLoader(function($name) use ($zendLoader) { 
    $zendLoader->autoload();

    return class_exists($name, false);
});
@schmittjoh schmittjoh closed this
@Fgruntjes

The problem has nothing to do with the AnnotationRegistry. Its the fact that Doctrine\Common\ClassLoader::classExists() uses spl_autoload_functions() to see if it can load a class. In my application we have multiple ZF2 autoloaders registered with spl_autoload_register(). This function does not dictate a return value however the Doctrine\Common\ClassLoader::classExists() does not work properly if there are auto load methods / functions registered without a return value.

@schmittjoh
Collaborator

Ups, I was too fast here!

Sorry :)

@schmittjoh schmittjoh reopened this
@beberlei beberlei was assigned
@Ocramius
Owner

This was handled in #216

@stof stof closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 17, 2012
  1. Replaced tab indenting with spaces

    Freek Gruntjes authored
This page is out of date. Refresh to see the latest.
View
5 lib/Doctrine/Common/ClassLoader.php
@@ -235,9 +235,12 @@ public static function classExists($className)
} else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
return true;
}
+ if (class_exists($className, false) || interface_exists($className, false)) {
+ return true;
+ }
}
- return class_exists($className, false) || interface_exists($className, false);
+ return false;
}
/**
View
21 tests/Doctrine/Tests/Common/ClassLoaderTest.php
@@ -33,7 +33,28 @@ public function testClassExists()
$this->assertTrue(ClassLoader::classExists('ClassLoaderTest\ClassD'));
spl_autoload_unregister($badLoader);
}
+
+ public function testClassExistsWithMultipleNonReturningAutoloaders()
+ {
+ $this->assertFalse(ClassLoader::classExists('ClassLoaderTest\ClassE'));
+ $nonReturnLoader = function($className) {
+ require __DIR__ . '/ClassLoaderTest/ClassE.php';
+ };
+ $nonReturnLoader2 = function($className) {
+ if (class_exists($className, false)) {
+ \PHPUnit_Framework_Assert::fail('Class load called twice for same class.');
+ }
+ require __DIR__ . '/ClassLoaderTest/ClassE.php';
+ };
+ spl_autoload_register($nonReturnLoader);
+ spl_autoload_register($nonReturnLoader2);
+
+ $this->assertTrue(ClassLoader::classExists('ClassLoaderTest\ClassE'));
+ spl_autoload_unregister($nonReturnLoader);
+ spl_autoload_unregister($nonReturnLoader2);
+ }
+
public function testGetClassLoader()
{
$cl = new ClassLoader('ClassLoaderTest', __DIR__);
View
5 tests/Doctrine/Tests/Common/ClassLoaderTest/ClassE.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace ClassLoaderTest;
+
+class ClassE {}
Something went wrong with that request. Please try again.