* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\ClassLoader; /** * ClassCollectionLoader. * * @author Fabien Potencier */ class ClassCollectionLoader { static private $loaded; static private $seen; /** * Loads a list of classes and caches them in one big file. * * @param array $classes An array of classes to load * @param string $cacheDir A cache directory * @param string $name The cache name prefix * @param Boolean $autoReload Whether to flush the cache when the cache is stale or not * @param Boolean $adaptive Whether to remove already declared classes or not * @param string $extension File extension of the resulting file * * @throws \InvalidArgumentException When class can't be loaded */ static public function load($classes, $cacheDir, $name, $autoReload, $adaptive = false, $extension = '.php') { // each $name can only be loaded once per PHP process if (isset(self::$loaded[$name])) { return; } self::$loaded[$name] = true; $declared = array_merge(get_declared_classes(), get_declared_interfaces()); if (function_exists('get_declared_traits')) { $declared = array_merge($declared, get_declared_traits()); } if ($adaptive) { // don't include already declared classes $classes = array_diff($classes, $declared); // the cache is different depending on which classes are already declared $name = $name.'-'.substr(md5(implode('|', $classes)), 0, 5); } $classes = array_unique($classes); $cache = $cacheDir.'/'.$name.$extension; // auto-reload $reload = false; if ($autoReload) { $metadata = $cacheDir.'/'.$name.$extension.'.meta'; if (!is_file($metadata) || !is_file($cache)) { $reload = true; } else { $time = filemtime($cache); $meta = unserialize(file_get_contents($metadata)); sort($meta[1]); sort($classes); if ($meta[1] != $classes) { $reload = true; } else { foreach ($meta[0] as $resource) { if (!is_file($resource) || filemtime($resource) > $time) { $reload = true; break; } } } } } if (!$reload && is_file($cache)) { require_once $cache; return; } $files = array(); $content = ''; foreach (self::getOrderedClasses($classes) as $class) { if (in_array($class->getName(), $declared)) { continue; } $files[] = $class->getFileName(); $c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName())); // add namespace declaration for global code if (!$class->inNamespace()) { $c = "\nnamespace\n{\n".self::stripComments($c)."\n}\n"; } else { $c = self::fixNamespaceDeclarations('getName()])) { return array(); } self::$seen[$class->getName()] = true; $classes = array($class); $parent = $class; while (($parent = $parent->getParentClass()) && $parent->isUserDefined() && !isset(self::$seen[$parent->getName()])) { self::$seen[$parent->getName()] = true; array_unshift($classes, $parent); } if (function_exists('get_declared_traits')) { foreach ($classes as $c) { foreach (self::getTraits($c) as $trait) { self::$seen[$trait->getName()] = true; array_unshift($classes, $trait); } } } foreach ($class->getInterfaces() as $interface) { if ($interface->isUserDefined() && !isset(self::$seen[$interface->getName()])) { self::$seen[$interface->getName()] = true; array_unshift($classes, $interface); } } return $classes; } static private function getTraits(\ReflectionClass $class) { $traits = $class->getTraits(); $classes = array(); while ($trait = array_pop($traits)) { if ($trait->isUserDefined() && !isset(self::$seen[$trait->getName()])) { $classes[] = $trait; $traits = array_merge($traits, $trait->getTraits()); } } return $classes; } }