diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md index 89a724b769..138b054cf0 100644 --- a/CHANGELOG-2.1.md +++ b/CHANGELOG-2.1.md @@ -178,6 +178,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c ### ClassLoader + * added a DebugClassLoader able to wrap any autoloader providing a findFile method * added a new ApcClassLoader using composition to wrap other loaders * added a new ClassLoader which does not distinguish between namespaced and pear-like classes (as the PEAR convention is a subset of PSR-0) and supports using Composer's namespace maps diff --git a/src/Symfony/Component/ClassLoader/DebugClassLoader.php b/src/Symfony/Component/ClassLoader/DebugClassLoader.php new file mode 100644 index 0000000000..b6f7968bca --- /dev/null +++ b/src/Symfony/Component/ClassLoader/DebugClassLoader.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ClassLoader; + +/** + * Autoloader checking if the class is really defined in the file found. + * + * The DebugClassLoader will wrap all registered autoloaders providing a + * findFile method and will throw an exception if a file is found but does + * not declare the class. + * + * @author Fabien Potencier + * @author Christophe Coevoet + * + * @api + */ +class DebugClassLoader +{ + private $classFinder; + + /** + * Constructor. + * + * @param object $classFinder + * + * @api + */ + public function __construct($classFinder) + { + $this->classFinder = $classFinder; + } + + /** + * Replaces all autoloaders implementing a findFile method by a DebugClassLoader wrapper. + */ + static public function enable() + { + if (!is_array($functions = spl_autoload_functions())) { + return; + } + + foreach ($functions as $function) { + spl_autoload_unregister($function); + } + + foreach ($functions as $function) { + if (is_array($function) && method_exists($function[0], 'findFile')) { + $function = array(new static($function[0]), 'loadClass'); + } + + spl_autoload_register($function); + } + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return Boolean|null True, if loaded + */ + public function loadClass($class) + { + if ($file = $this->classFinder->findFile($class)) { + require $file; + + if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) { + throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file)); + } + + return true; + } + } +} diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index d1fb733d1b..85483fd3c2 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -34,7 +34,7 @@ use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\Config\Loader\DelegatingLoader; use Symfony\Component\Config\ConfigCache; use Symfony\Component\ClassLoader\ClassCollectionLoader; -use Symfony\Component\ClassLoader\DebugUniversalClassLoader; +use Symfony\Component\ClassLoader\DebugClassLoader; /** * The Kernel is the heart of the Symfony system. @@ -91,7 +91,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface ini_set('display_errors', 1); error_reporting(-1); - DebugUniversalClassLoader::enable(); + DebugClassLoader::enable(); ErrorHandler::register($this->errorReportingLevel); if ('cli' !== php_sapi_name()) { ExceptionHandler::register();