Przeglądaj źródła

[Autoload] remove closures because of a bug in APC

https://bugs.php.net/bug.php?id=52144
https://bugs.php.net/bug.php?id=61576
Victor Berchet 12 lat temu
rodzic
commit
963fedc9a5

+ 67 - 37
src/Composer/Autoload/AutoloadGenerator.php

@@ -25,7 +25,7 @@ use Composer\Util\Filesystem;
  */
 class AutoloadGenerator
 {
-    public function dump(Config $config, RepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir)
+    public function dump(Config $config, RepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $classSuffix = '')
     {
         $filesystem = new Filesystem();
         $filesystem->ensureDirectoryExists($config->get('vendor-dir'));
@@ -93,23 +93,24 @@ EOF;
             $baseDirFromVendorDirCode = $filesystem->findShortestPathCode($vendorPath, getcwd(), true);
 
             $targetDirLoader = <<<EOF
-    spl_autoload_register(function(\$class) {
-        \$dir = $baseDirFromVendorDirCode . '/';
-        \$prefixes = array($prefixes);
-        foreach (\$prefixes as \$prefix) {
-            if (0 !== strpos(\$class, \$prefix)) {
-                continue;
-            }
-            \$path = \$dir . implode('/', array_slice(explode('\\\\', \$class), $levels)).'.php';
-            if (!\$path = stream_resolve_include_path(\$path)) {
-                return false;
-            }
-            require \$path;
 
-            return true;
-        }
-    });
+        public static function autoload(\$class)
+        {
+            \$dir = $baseDirFromVendorDirCode . '/';
+            \$prefixes = array($prefixes);
+            foreach (\$prefixes as \$prefix) {
+                if (0 !== strpos(\$class, \$prefix)) {
+                    continue;
+                }
+                \$path = \$dir . implode('/', array_slice(explode('\\\\', \$class), $levels)).'.php';
+                if (!\$path = stream_resolve_include_path(\$path)) {
+                    return false;
+                }
+                require \$path;
 
+                return true;
+            }
+        }
 
 EOF;
         }
@@ -127,7 +128,7 @@ EOF;
         $filesCode = "";
         $autoloads['files'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['files']));
         foreach ($autoloads['files'] as $functionFile) {
-            $filesCode .= '    require '.$this->getPathCode($filesystem, $relVendorPath, $vendorPath, $functionFile).";\n";
+            $filesCode .= '            require '.$this->getPathCode($filesystem, $relVendorPath, $vendorPath, $functionFile).";\n";
         }
 
         file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile);
@@ -135,7 +136,7 @@ EOF;
         if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $relVendorPath, $vendorPath, $vendorPathCode, $appBaseDirCode)) {
             file_put_contents($targetDir.'/include_paths.php', $includePathFile);
         }
-        file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, true, true, (bool) $includePathFile, $targetDirLoader, $filesCode));
+        file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, true, true, (bool) $includePathFile, $targetDirLoader, $filesCode, $classSuffix));
         copy(__DIR__.'/ClassLoader.php', $targetDir.'/ClassLoader.php');
     }
 
@@ -277,8 +278,14 @@ EOF;
         return $baseDir.var_export($path, true);
     }
 
-    protected function getAutoloadFile($vendorPathToTargetDirCode, $usePSR0, $useClassMap, $useIncludePath, $targetDirLoader, $filesCode)
+    protected function getAutoloadFile($vendorPathToTargetDirCode, $usePSR0, $useClassMap, $useIncludePath, $targetDirLoader, $filesCode, $classSuffix)
     {
+        // TODO the class ComposerAutoloaderInit should be revert to a closure
+        // when APC has been fixed:
+        // - https://github.com/composer/composer/issues/959
+        // - https://bugs.php.net/bug.php?id=52144
+        // - https://bugs.php.net/bug.php?id=61576
+
         if ($filesCode) {
             $filesCode = "\n".$filesCode;
         }
@@ -291,18 +298,22 @@ if (!class_exists('Composer\\\\Autoload\\\\ClassLoader', false)) {
     require $vendorPathToTargetDirCode . '/ClassLoader.php';
 }
 
-return call_user_func(function() {
-    \$loader = new \\Composer\\Autoload\\ClassLoader();
-    \$composerDir = $vendorPathToTargetDirCode;
+if (!class_exists('ComposerAutoloaderInit$classSuffix', false)) {
+    class ComposerAutoloaderInit$classSuffix
+    {
+        public static function getLoader()
+        {
+            \$loader = new \\Composer\\Autoload\\ClassLoader();
+            \$composerDir = $vendorPathToTargetDirCode;
 
 
 HEADER;
 
         if ($useIncludePath) {
             $file .= <<<'INCLUDE_PATH'
-    $includePaths = require $composerDir . '/include_paths.php';
-    array_push($includePaths, get_include_path());
-    set_include_path(join(PATH_SEPARATOR, $includePaths));
+            $includePaths = require $composerDir . '/include_paths.php';
+            array_push($includePaths, get_include_path());
+            set_include_path(join(PATH_SEPARATOR, $includePaths));
 
 
 INCLUDE_PATH;
@@ -310,10 +321,10 @@ INCLUDE_PATH;
 
         if ($usePSR0) {
             $file .= <<<'PSR0'
-    $map = require $composerDir . '/autoload_namespaces.php';
-    foreach ($map as $namespace => $path) {
-        $loader->add($namespace, $path);
-    }
+            $map = require $composerDir . '/autoload_namespaces.php';
+            foreach ($map as $namespace => $path) {
+                $loader->add($namespace, $path);
+            }
 
 
 PSR0;
@@ -321,23 +332,42 @@ PSR0;
 
         if ($useClassMap) {
             $file .= <<<'CLASSMAP'
-    $classMap = require $composerDir . '/autoload_classmap.php';
-    if ($classMap) {
-        $loader->addClassMap($classMap);
-    }
+            $classMap = require $composerDir . '/autoload_classmap.php';
+            if ($classMap) {
+                $loader->addClassMap($classMap);
+            }
 
 
 CLASSMAP;
         }
 
+        if ($targetDirLoader) {
+            $file .= <<<REGISTER_AUTOLOAD
+            spl_autoload_register(array('ComposerAutoloaderInit$classSuffix', 'autoload'));
+
+
+REGISTER_AUTOLOAD;
+
+        }
+
+        $file .= <<<METHOD_FOOTER
+            \$loader->register();
+$filesCode
+            return \$loader;
+        }
+
+METHOD_FOOTER;
+
         $file .= $targetDirLoader;
 
         return $file . <<<FOOTER
-    \$loader->register();
-$filesCode
-    return \$loader;
-});
+    }
+}
+
+return ComposerAutoloaderInit$classSuffix::getLoader();
 
 FOOTER;
+
     }
 }
+

+ 12 - 12
tests/Composer/Test/Autoload/AutoloadGeneratorTest.php

@@ -95,7 +95,7 @@ class AutoloadGeneratorTest extends TestCase
 
         $this->createClassFile($this->workingDir);
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', '_1');
         $this->assertAutoloadFiles('main', $this->vendorDir.'/composer');
         $this->assertAutoloadFiles('classmap', $this->vendorDir.'/composer', 'classmap');
     }
@@ -120,7 +120,7 @@ class AutoloadGeneratorTest extends TestCase
 
         $this->createClassFile($this->vendorDir);
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', '_2');
         $this->assertAutoloadFiles('main3', $this->vendorDir.'/composer');
         $this->assertAutoloadFiles('classmap3', $this->vendorDir.'/composer', 'classmap');
     }
@@ -140,7 +140,7 @@ class AutoloadGeneratorTest extends TestCase
         $this->vendorDir .= '/subdir';
         mkdir($this->vendorDir.'/composer', 0777, true);
         $this->createClassFile($this->workingDir);
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', '_3');
         $this->assertAutoloadFiles('main2', $this->vendorDir.'/composer');
         $this->assertAutoloadFiles('classmap2', $this->vendorDir.'/composer', 'classmap');
     }
@@ -157,7 +157,7 @@ class AutoloadGeneratorTest extends TestCase
             ->method('getPackages')
             ->will($this->returnValue(array()));
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', 'TargetDir');
         $this->assertFileEquals(__DIR__.'/Fixtures/autoload_target_dir.php', $this->vendorDir.'/autoload.php');
     }
 
@@ -177,7 +177,7 @@ class AutoloadGeneratorTest extends TestCase
             ->will($this->returnValue($packages));
 
         mkdir($this->vendorDir.'/composer', 0777, true);
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', '_5');
         $this->assertAutoloadFiles('vendors', $this->vendorDir.'/composer');
         $this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated, even if empty.");
     }
@@ -204,7 +204,7 @@ class AutoloadGeneratorTest extends TestCase
         file_put_contents($this->vendorDir.'/b/b/src/b.php', '<?php class ClassMapBar {}');
         file_put_contents($this->vendorDir.'/b/b/lib/c.php', '<?php class ClassMapBaz {}');
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', '_6');
         $this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
         $this->assertEquals(
             array(
@@ -241,7 +241,7 @@ class AutoloadGeneratorTest extends TestCase
         file_put_contents($this->vendorDir.'/b/b/test.php', '<?php class ClassMapBar {}');
         file_put_contents($this->vendorDir.'/c/c/foo/test.php', '<?php class ClassMapBaz {}');
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', '_7');
         $this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
         $this->assertEquals(
             array(
@@ -273,7 +273,7 @@ class AutoloadGeneratorTest extends TestCase
         file_put_contents($this->vendorDir.'/a/a/test.php', '<?php function testFilesAutoloadGeneration1() {}');
         file_put_contents($this->vendorDir.'/b/b/test2.php', '<?php function testFilesAutoloadGeneration2() {}');
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', 'FilesAutoload');
         $this->assertFileEquals(__DIR__.'/Fixtures/autoload_functions.php', $this->vendorDir.'/autoload.php');
 
         include $this->vendorDir . '/autoload.php';
@@ -297,7 +297,7 @@ class AutoloadGeneratorTest extends TestCase
             ->will($this->returnValue($packages));
 
         mkdir($this->vendorDir.'/composer', 0777, true);
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer');
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', '_9');
         $this->assertAutoloadFiles('override_vendors', $this->vendorDir.'/composer');
     }
 
@@ -325,7 +325,7 @@ class AutoloadGeneratorTest extends TestCase
 
         mkdir($this->vendorDir."/composer", 0777, true);
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, "composer");
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, "composer", '_10');
 
         $this->assertFileEquals(__DIR__.'/Fixtures/include_paths.php', $this->vendorDir.'/composer/include_paths.php');
         $this->assertEquals(
@@ -354,7 +354,7 @@ class AutoloadGeneratorTest extends TestCase
 
         mkdir($this->vendorDir."/composer", 0777, true);
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, "composer");
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, "composer", '_11');
 
         $oldIncludePath = get_include_path();
 
@@ -382,7 +382,7 @@ class AutoloadGeneratorTest extends TestCase
 
         mkdir($this->vendorDir."/composer", 0777, true);
 
-        $this->generator->dump($this->config, $this->repository, $package, $this->im, "composer");
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, "composer", '_12');
 
         $this->assertFalse(file_exists($this->vendorDir."/composer/include_paths.php"));
     }

+ 24 - 16
tests/Composer/Test/Autoload/Fixtures/autoload_functions.php

@@ -5,24 +5,32 @@ if (!class_exists('Composer\\Autoload\\ClassLoader', false)) {
     require __DIR__ . '/composer' . '/ClassLoader.php';
 }
 
-return call_user_func(function() {
-    $loader = new \Composer\Autoload\ClassLoader();
-    $composerDir = __DIR__ . '/composer';
+if (!class_exists('ComposerAutoloaderInitFilesAutoload', false)) {
+    class ComposerAutoloaderInitFilesAutoload
+    {
+        public static function getLoader()
+        {
+            $loader = new \Composer\Autoload\ClassLoader();
+            $composerDir = __DIR__ . '/composer';
 
-    $map = require $composerDir . '/autoload_namespaces.php';
-    foreach ($map as $namespace => $path) {
-        $loader->add($namespace, $path);
-    }
+            $map = require $composerDir . '/autoload_namespaces.php';
+            foreach ($map as $namespace => $path) {
+                $loader->add($namespace, $path);
+            }
 
-    $classMap = require $composerDir . '/autoload_classmap.php';
-    if ($classMap) {
-        $loader->addClassMap($classMap);
-    }
+            $classMap = require $composerDir . '/autoload_classmap.php';
+            if ($classMap) {
+                $loader->addClassMap($classMap);
+            }
+
+            $loader->register();
 
-    $loader->register();
+            require $vendorDir . '/a/a/test.php';
+            require $vendorDir . '/b/b/test2.php';
 
-    require $vendorDir . '/a/a/test.php';
-    require $vendorDir . '/b/b/test2.php';
+            return $loader;
+        }
+    }
+}
 
-    return $loader;
-});
+return ComposerAutoloaderInitFilesAutoload::getLoader();

+ 39 - 28
tests/Composer/Test/Autoload/Fixtures/autoload_target_dir.php

@@ -5,38 +5,49 @@ if (!class_exists('Composer\\Autoload\\ClassLoader', false)) {
     require __DIR__ . '/composer' . '/ClassLoader.php';
 }
 
-return call_user_func(function() {
-    $loader = new \Composer\Autoload\ClassLoader();
-    $composerDir = __DIR__ . '/composer';
+if (!class_exists('ComposerAutoloaderInitTargetDir', false)) {
+    class ComposerAutoloaderInitTargetDir
+    {
+        public static function getLoader()
+        {
+            $loader = new \Composer\Autoload\ClassLoader();
+            $composerDir = __DIR__ . '/composer';
+
+            $map = require $composerDir . '/autoload_namespaces.php';
+            foreach ($map as $namespace => $path) {
+                $loader->add($namespace, $path);
+            }
 
-    $map = require $composerDir . '/autoload_namespaces.php';
-    foreach ($map as $namespace => $path) {
-        $loader->add($namespace, $path);
-    }
+            $classMap = require $composerDir . '/autoload_classmap.php';
+            if ($classMap) {
+                $loader->addClassMap($classMap);
+            }
 
-    $classMap = require $composerDir . '/autoload_classmap.php';
-    if ($classMap) {
-        $loader->addClassMap($classMap);
-    }
+            spl_autoload_register(array('ComposerAutoloaderInitTargetDir', 'autoload'));
 
-    spl_autoload_register(function($class) {
-        $dir = dirname(__DIR__) . '/';
-        $prefixes = array('Main\\Foo', 'Main\\Bar');
-        foreach ($prefixes as $prefix) {
-            if (0 !== strpos($class, $prefix)) {
-                continue;
-            }
-            $path = $dir . implode('/', array_slice(explode('\\', $class), 2)).'.php';
-            if (!$path = stream_resolve_include_path($path)) {
-                return false;
-            }
-            require $path;
+            $loader->register();
 
-            return true;
+            return $loader;
         }
-    });
 
-    $loader->register();
+        public static function autoload($class)
+        {
+            $dir = dirname(__DIR__) . '/';
+            $prefixes = array('Main\\Foo', 'Main\\Bar');
+            foreach ($prefixes as $prefix) {
+                if (0 !== strpos($class, $prefix)) {
+                    continue;
+                }
+                $path = $dir . implode('/', array_slice(explode('\\', $class), 2)).'.php';
+                if (!$path = stream_resolve_include_path($path)) {
+                    return false;
+                }
+                require $path;
+
+                return true;
+            }
+        }
+    }
+}
 
-    return $loader;
-});
+return ComposerAutoloaderInitTargetDir::getLoader();