فهرست منبع

Load most specific namespaces always, and dependents before dependencies when building classmaps

This also adds notifications of duplicate classes
Jordi Boggiano 10 سال پیش
والد
کامیت
943107cfe7
2فایلهای تغییر یافته به همراه30 افزوده شده و 7 حذف شده
  1. 29 6
      src/Composer/Autoload/AutoloadGenerator.php
  2. 1 1
      src/Composer/Autoload/ClassMapGenerator.php

+ 29 - 6
src/Composer/Autoload/AutoloadGenerator.php

@@ -174,10 +174,21 @@ EOF;
         // flatten array
         $classMap = array();
         if ($scanPsr0Packages) {
+            $namespacesToScan = array();
+
             // Scan the PSR-0/4 directories for class files, and add them to the class map
             foreach (array('psr-0', 'psr-4') as $psrType) {
                 foreach ($autoloads[$psrType] as $namespace => $paths) {
-                    foreach ($paths as $dir) {
+                    $namespacesToScan[$namespace][] = array('paths' => $paths, 'type' => $psrType);
+                }
+            }
+
+            krsort($namespacesToScan);
+
+            foreach ($namespacesToScan as $namespace => $groups) {
+                foreach ($groups as $group) {
+                    $psrType = $group['type'];
+                    foreach ($group['paths'] as $dir) {
                         $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir);
                         if (!is_dir($dir)) {
                             continue;
@@ -190,9 +201,14 @@ EOF;
 
                         $namespaceFilter = $namespace === '' ? null : $namespace;
                         foreach (ClassMapGenerator::createMap($dir, $whitelist, $this->io, $namespaceFilter) as $class => $path) {
+                            $pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
                             if (!isset($classMap[$class])) {
-                                $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
-                                $classMap[$class] = $path.",\n";
+                                $classMap[$class] = $pathCode.",\n";
+                            } elseif ($this->io && $classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class].' '.$path, '\\', '/'))) {
+                                $this->io->writeError(
+                                    '<warning>Warning: Ambiguous class resolution, "'.$class.'"'.
+                                    ' was found in both "'.str_replace(array('$vendorDir . \'', "',\n"), array($vendorPath, ''), $classMap[$class]).'" and "'.$path.'", the first will be used.</warning>'
+                                );
                             }
                         }
                     }
@@ -202,8 +218,15 @@ EOF;
 
         foreach ($autoloads['classmap'] as $dir) {
             foreach (ClassMapGenerator::createMap($dir, null, $this->io) as $class => $path) {
-                $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
-                $classMap[$class] = $path.",\n";
+                $pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
+                if (!isset($classMap[$class])) {
+                    $classMap[$class] = $pathCode.",\n";
+                } elseif ($this->io && $classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class].' '.$path, '\\', '/'))) {
+                    $this->io->writeError(
+                        '<warning>Warning: Ambiguous class resolution, "'.$class.'"'.
+                        ' was found in both "'.str_replace(array('$vendorDir . \'', "',\n"), array($vendorPath, ''), $classMap[$class]).'" and "'.$path.'", the first will be used.</warning>'
+                    );
+                }
             }
         }
 
@@ -310,7 +333,7 @@ EOF;
 
         $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage);
         $psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $mainPackage);
-        $classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap', $mainPackage);
+        $classmap = $this->parseAutoloadsType(array_reverse($sortedPackageMap), 'classmap', $mainPackage);
         $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage);
 
         krsort($psr0);

+ 1 - 1
src/Composer/Autoload/ClassMapGenerator.php

@@ -91,7 +91,7 @@ class ClassMapGenerator
 
                 if (!isset($map[$class])) {
                     $map[$class] = $filePath;
-                } elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
+                } elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
                     $io->writeError(
                         '<warning>Warning: Ambiguous class resolution, "'.$class.'"'.
                         ' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.</warning>'