<NME> DirectoryScanner.php
<BEF> <?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\Code\Scanner;

use RecursiveDirectoryIterator;
    protected $directories          = array();
    protected $fileScannerFileClass = 'Zend\Code\Scanner\FileScanner';
    protected $fileScanners         = array();
    
    public function __construct($directory = null)
    {
use function is_string;
use function pathinfo;
use function realpath;
use function sprintf;

class DirectoryScanner implements ScannerInterface
{
    /**
     * @var bool
     */
    protected $isScanned = false;

    /**
     * @var string[]|DirectoryScanner[]
     */
    protected $directories = [];

    /**
     * @var FileScanner[]
     */
    protected $fileScanners = [];

    /**
     * @var array
     */
    protected $classToFileScanner;

    /**
     * @param null|string|array $directory
     */
    public function __construct($directory = null)
    {
        if ($directory) {
            if (is_string($directory)) {
                $this->addDirectory($directory);
            } elseif (is_array($directory)) {
                foreach ($directory as $d) {
                    $this->addDirectory($d);
                }
            }
        }
    }

    /**
     * @param  DirectoryScanner|string $directory
     * @return void
     * @throws Exception\InvalidArgumentException
     */
    public function addDirectory($directory)
    {
        if ($directory instanceof DirectoryScanner) {
            $this->directories[] = $directory;
        } elseif (is_string($directory)) {
            $realDir = realpath($directory);
            if (! $realDir || ! is_dir($realDir)) {
                throw new Exception\InvalidArgumentException(sprintf(
                    'Directory "%s" does not exist',
                    $realDir
                ));
            }
            $this->directories[] = $realDir;
        } else {
            throw new Exception\InvalidArgumentException(
                'The argument provided was neither a DirectoryScanner or directory path'
            );
        }
    }

    /**
     * @param  DirectoryScanner $directoryScanner
     * @return void
     */
    public function addDirectoryScanner(DirectoryScanner $directoryScanner)
    {
        $this->addDirectory($directoryScanner);
    }
    {
        $this->scan();
        
        $classes = array();
        foreach ($this->fileScanners as $scannerFile) {
            /* @var $scannerFile Zend\Code\Scanner\FileScanner */
            $classes = array_merge($classes, $scannerFile->getClasses($returnScannerClass));
        }
        
        if ($returnDerivedScannerClass) {
            foreach ($classes as $index => $class) {
                if ($class instanceof ClassScanner) {
                    $classes[$index] = new DerivedClassScanner($class, $this);
                }
            }
        }
        
        return $classes;
    }
    
    public function hasClass($class)
    {
        return (in_array($class, $this->getClasses()));
    }
    
    public function getClass($class, $returnScannerClass = true, $returnDerivedScannerClass = false)
    {
        $this->scan();
        
        foreach ($this->fileScanners as $scannerFile) {
            /* @var $scannerFile Zend\Code\Scanner\FileScanner */
            $classesInFileScanner = $scannerFile->getClasses(false);
            if (in_array($class, $classesInFileScanner)) {
                $returnClass = $scannerFile->getClass($class, $returnScannerClass);
            }
        }
        
        if (isset($returnClass) && $returnClass instanceof ClassScanner && $returnDerivedScannerClass) {
            return new DerivedClassScanner($returnClass, $this);
        } elseif (isset($returnClass)) {
            return $returnClass;
        }
        
        throw new Exception\InvalidArgumentException('Class not found.');
    }

    public static function export() {}
    public function __toString() {} 
}
        return array_keys($this->classToFileScanner);
    }

    /**
     * @param  bool  $returnDerivedScannerClass
     * @return array
     */
    public function getClasses($returnDerivedScannerClass = false)
    {
        $this->scan();

        if ($this->classToFileScanner === null) {
            $this->createClassToFileScannerCache();
        }

        $returnClasses = [];
        foreach ($this->classToFileScanner as $className => $fsIndex) {
            $classScanner = $this->fileScanners[$fsIndex]->getClass($className);
            if ($returnDerivedScannerClass) {
                $classScanner = new DerivedClassScanner($classScanner, $this);
            }
            $returnClasses[] = $classScanner;
        }

        return $returnClasses;
    }

    /**
     * @param  string $class
     * @return bool
     */
    public function hasClass($class)
    {
        $this->scan();

        if ($this->classToFileScanner === null) {
            $this->createClassToFileScannerCache();
        }

        return isset($this->classToFileScanner[$class]);
    }

    /**
     * @param  string $class
     * @param  bool $returnDerivedScannerClass
     * @return ClassScanner|DerivedClassScanner
     * @throws Exception\InvalidArgumentException
     */
    public function getClass($class, $returnDerivedScannerClass = false)
    {
        $this->scan();

        if ($this->classToFileScanner === null) {
            $this->createClassToFileScannerCache();
        }

        if (! isset($this->classToFileScanner[$class])) {
            throw new Exception\InvalidArgumentException('Class not found.');
        }

        /** @var FileScanner $fs */
        $fs          = $this->fileScanners[$this->classToFileScanner[$class]];
        $returnClass = $fs->getClass($class);

        if ($returnClass instanceof ClassScanner && $returnDerivedScannerClass) {
            return new DerivedClassScanner($returnClass, $this);
        }

        return $returnClass;
    }

    /**
     * Create class to file scanner cache
     *
     * @return void
     */
    protected function createClassToFileScannerCache()
    {
        if ($this->classToFileScanner !== null) {
            return;
        }

        $this->classToFileScanner = [];

        /** @var FileScanner $fileScanner */
        foreach ($this->fileScanners as $fsIndex => $fileScanner) {
            $fsClasses = $fileScanner->getClassNames();
            foreach ($fsClasses as $fsClassName) {
                $this->classToFileScanner[$fsClassName] = $fsIndex;
            }
        }
    }

    /**
     * Export
     *
     * @todo implement method
     */
    public static function export()
    {
        // @todo
    }

    /**
     * __ToString
     *
     * @todo implement method
     */
    public function __toString()
    {
        // @todo
    }
}

<MSG> Added exclution of class names to Zend\Di\Definition\IntrospectionRuleset
Fixed bug in Zend\Code\Scanner\ClassScanner when finding method names
Added caching of classes to filescanners in Zend\Code\Scanner\DirectoryScanner

<DFF> @@ -13,6 +13,7 @@ class DirectoryScanner implements Scanner
     protected $directories          = array();
     protected $fileScannerFileClass = 'Zend\Code\Scanner\FileScanner';
     protected $fileScanners         = array();
+    protected $classToFileScanner   = null;
     
     public function __construct($directory = null)
     {
@@ -95,49 +96,74 @@ class DirectoryScanner implements Scanner
     {
         $this->scan();
         
-        $classes = array();
-        foreach ($this->fileScanners as $scannerFile) {
-            /* @var $scannerFile Zend\Code\Scanner\FileScanner */
-            $classes = array_merge($classes, $scannerFile->getClasses($returnScannerClass));
+        if ($this->classToFileScanner === null) {
+            $this->createClassToFileScannerCache();
         }
         
-        if ($returnDerivedScannerClass) {
-            foreach ($classes as $index => $class) {
-                if ($class instanceof ClassScanner) {
-                    $classes[$index] = new DerivedClassScanner($class, $this);
-                }
+        if ($returnScannerClass == false) {
+            return array_keys($this->classToFileScanner);
+        }
+        
+        $returnClasses = array();
+        foreach ($this->classToFileScanner as $className => $fsIndex) {
+            $classScanner = $this->fileScanners[$fsIndex]->getClass($className, $returnScannerClass);
+            if ($returnDerivedScannerClass) {
+                $classScanner = new DerivedClassScanner($classScanner, $this);
             }
+            $returnClasses[] = $classScanner;
         }
         
-        return $classes;
+        return $returnClasses;
     }
     
     public function hasClass($class)
     {
-        return (in_array($class, $this->getClasses()));
+        $this->scan();
+        
+        if ($this->classToFileScanner === null) {
+            $this->createClassToFileScannerCache();
+        }
+        
+        return (isset($this->classToFileScanner[$class]));
     }
     
     public function getClass($class, $returnScannerClass = true, $returnDerivedScannerClass = false)
     {
         $this->scan();
         
-        foreach ($this->fileScanners as $scannerFile) {
-            /* @var $scannerFile Zend\Code\Scanner\FileScanner */
-            $classesInFileScanner = $scannerFile->getClasses(false);
-            if (in_array($class, $classesInFileScanner)) {
-                $returnClass = $scannerFile->getClass($class, $returnScannerClass);
-            }
+        if ($this->classToFileScanner === null) {
+            $this->createClassToFileScannerCache();
         }
         
-        if (isset($returnClass) && $returnClass instanceof ClassScanner && $returnDerivedScannerClass) {
-            return new DerivedClassScanner($returnClass, $this);
-        } elseif (isset($returnClass)) {
-            return $returnClass;
+        if (!isset($this->classToFileScanner[$class])) {
+            throw new Exception\InvalidArgumentException('Class not found.');
         }
         
-        throw new Exception\InvalidArgumentException('Class not found.');
+        $fs = $this->fileScanners[$this->classToFileScanner[$class]];
+        $returnClass = $fs->getClass($class, $returnScannerClass);
+        
+        if (($returnClass instanceof ClassScanner) && $returnDerivedScannerClass) {
+            return new DerivedClassScanner($returnClass, $this);
+        }
+
+        return $returnClass;
     }
 
+    protected function createClassToFileScannerCache()
+    {
+        if ($this->classToFileScanner !== null) {
+            return;
+        }
+        
+        $this->classToFileScanner = array();
+        foreach ($this->fileScanners as $fsIndex => $fileScanner) {
+            $fsClasses = $fileScanner->getClasses();
+            foreach ($fsClasses as $fsClassName) {
+                $this->classToFileScanner[$fsClassName] = $fsIndex;
+            }
+        }
+    }
+    
     public static function export() {}
     public function __toString() {} 
 }

Added exclution of class names to Zend\Di\Definition\IntrospectionRuleset Fixed bug in Zend\Code\Scanner\ClassScanner when finding method names Added caching of classes to filescanners in Zend\Code\Scanner\DirectoryScanner