diff options
| author | Greg Roach <fisharebest@gmail.com> | 2018-05-31 09:45:16 +0100 |
|---|---|---|
| committer | Greg Roach <fisharebest@gmail.com> | 2018-05-31 09:57:27 +0100 |
| commit | ffe6005c11fdad01969e67c039b0d73beb0232e9 (patch) | |
| tree | 6d8df2e00473a813fef26155db549f9a969092f7 /vendor/symfony/debug/DebugClassLoader.php | |
| parent | bba27599b02e0b6f90f62348bb4fa32bd74056d0 (diff) | |
| download | webtrees-ffe6005c11fdad01969e67c039b0d73beb0232e9.tar.gz webtrees-ffe6005c11fdad01969e67c039b0d73beb0232e9.tar.bz2 webtrees-ffe6005c11fdad01969e67c039b0d73beb0232e9.zip | |
Update minimum PHP version to 7.0.8 so that we can use the 3.4 LTS version of symfony
Diffstat (limited to 'vendor/symfony/debug/DebugClassLoader.php')
| -rw-r--r-- | vendor/symfony/debug/DebugClassLoader.php | 213 |
1 files changed, 135 insertions, 78 deletions
diff --git a/vendor/symfony/debug/DebugClassLoader.php b/vendor/symfony/debug/DebugClassLoader.php index 2e1d71808e..33e715a869 100644 --- a/vendor/symfony/debug/DebugClassLoader.php +++ b/vendor/symfony/debug/DebugClassLoader.php @@ -26,18 +26,17 @@ class DebugClassLoader { private $classLoader; private $isFinder; + private $loaded = array(); private static $caseCheck; + private static $checkedClasses = array(); private static $final = array(); private static $finalMethods = array(); private static $deprecated = array(); - private static $php7Reserved = array('int', 'float', 'bool', 'string', 'true', 'false', 'null'); + private static $internal = array(); + private static $internalMethods = array(); + private static $php7Reserved = array('int' => 1, 'float' => 1, 'bool' => 1, 'string' => 1, 'true' => 1, 'false' => 1, 'null' => 1); private static $darwinCache = array('/' => array('/', array())); - /** - * Constructor. - * - * @param callable $classLoader A class loader - */ public function __construct(callable $classLoader) { $this->classLoader = $classLoader; @@ -136,120 +135,153 @@ class DebugClassLoader */ public function loadClass($class) { - ErrorHandler::stackErrors(); + $e = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR); try { - if ($this->isFinder) { - if ($file = $this->classLoader[0]->findFile($class)) { - require_once $file; + if ($this->isFinder && !isset($this->loaded[$class])) { + $this->loaded[$class] = true; + if ($file = $this->classLoader[0]->findFile($class) ?: false) { + $wasCached = \function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file); + + require $file; + + if ($wasCached) { + return; + } } } else { call_user_func($this->classLoader, $class); $file = false; } } finally { - ErrorHandler::unstackErrors(); + error_reporting($e); } - $exists = class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); + $this->checkClass($class, $file); + } - if ($class && '\\' === $class[0]) { + private function checkClass($class, $file = null) + { + $exists = null === $file || \class_exists($class, false) || \interface_exists($class, false) || \trait_exists($class, false); + + if (null !== $file && $class && '\\' === $class[0]) { $class = substr($class, 1); } if ($exists) { + if (isset(self::$checkedClasses[$class])) { + return; + } + self::$checkedClasses[$class] = true; + $refl = new \ReflectionClass($class); + if (null === $file && $refl->isInternal()) { + return; + } $name = $refl->getName(); - if ($name !== $class && 0 === strcasecmp($name, $class)) { + if ($name !== $class && 0 === \strcasecmp($name, $class)) { throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name)); } - $parent = get_parent_class($class); + // Don't trigger deprecations for classes in the same vendor + if (2 > $len = 1 + (\strpos($name, '\\') ?: \strpos($name, '_'))) { + $len = 0; + $ns = ''; + } else { + $ns = \substr($name, 0, $len); + } + + // Detect annotations on the class + if (false !== $doc = $refl->getDocComment()) { + foreach (array('final', 'deprecated', 'internal') as $annotation) { + if (false !== \strpos($doc, $annotation) && preg_match('#\n \* @'.$annotation.'(?:( .+?)\.?)?\r?\n \*(?: @|/$)#s', $doc, $notice)) { + self::${$annotation}[$name] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; + } + } + } + + $parentAndTraits = \class_uses($name, false); + if ($parent = \get_parent_class($class)) { + $parentAndTraits[] = $parent; - // Not an interface nor a trait - if (class_exists($name, false)) { - if (preg_match('#\n \* @final(?:( .+?)\.?)?\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) { - self::$final[$name] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; + if (!isset(self::$checkedClasses[$parent])) { + $this->checkClass($parent); } - if ($parent && isset(self::$final[$parent])) { + if (isset(self::$final[$parent])) { @trigger_error(sprintf('The "%s" class is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $parent, self::$final[$parent], $name), E_USER_DEPRECATED); } + } - // Inherit @final annotations - self::$finalMethods[$name] = $parent && isset(self::$finalMethods[$parent]) ? self::$finalMethods[$parent] : array(); - - foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) { - if ($method->class !== $name) { - continue; - } - - if ($parent && isset(self::$finalMethods[$parent][$method->name])) { - @trigger_error(sprintf('%s It may change without further notice as of its next major version. You should not extend it from "%s".', self::$finalMethods[$parent][$method->name], $name), E_USER_DEPRECATED); - } + // Detect if the parent is annotated + foreach ($parentAndTraits + $this->getOwnInterfaces($name, $parent) as $use) { + if (!isset(self::$checkedClasses[$use])) { + $this->checkClass($use); + } + if (isset(self::$deprecated[$use]) && \strncmp($ns, $use, $len)) { + $type = class_exists($name, false) ? 'class' : (interface_exists($name, false) ? 'interface' : 'trait'); + $verb = class_exists($use, false) || interface_exists($name, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses'); - $doc = $method->getDocComment(); - if (false === $doc || false === strpos($doc, '@final')) { - continue; - } + @trigger_error(sprintf('The "%s" %s %s "%s" that is deprecated%s.', $name, $type, $verb, $use, self::$deprecated[$use]), E_USER_DEPRECATED); + } + if (isset(self::$internal[$use]) && \strncmp($ns, $use, $len)) { + @trigger_error(sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $name), E_USER_DEPRECATED); + } + } - if (preg_match('#\n\s+\* @final(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$)#s', $doc, $notice)) { - $message = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; - self::$finalMethods[$name][$method->name] = sprintf('The "%s::%s()" method is considered final%s.', $name, $method->name, $message); + // Inherit @final and @internal annotations for methods + self::$finalMethods[$name] = array(); + self::$internalMethods[$name] = array(); + foreach ($parentAndTraits as $use) { + foreach (array('finalMethods', 'internalMethods') as $property) { + if (isset(self::${$property}[$use])) { + self::${$property}[$name] = self::${$property}[$name] ? self::${$property}[$use] + self::${$property}[$name] : self::${$property}[$use]; } } } - if (in_array(strtolower($refl->getShortName()), self::$php7Reserved)) { - @trigger_error(sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED); - } elseif (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) { - self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]); - } else { - // Don't trigger deprecations for classes in the same vendor - if (2 > $len = 1 + (strpos($name, '\\', 1 + strpos($name, '\\')) ?: strpos($name, '_'))) { - $len = 0; - $ns = ''; - } else { - switch ($ns = substr($name, 0, $len)) { - case 'Symfony\Bridge\\': - case 'Symfony\Bundle\\': - case 'Symfony\Component\\': - $ns = 'Symfony\\'; - $len = strlen($ns); - break; - } + $isClass = \class_exists($name, false); + foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) { + if ($method->class !== $name) { + continue; } - if (!$parent || strncmp($ns, $parent, $len)) { - if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) { - @trigger_error(sprintf('The "%s" class extends "%s" that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED); - } + // Method from a trait + if ($method->getFilename() !== $refl->getFileName()) { + continue; + } - $parentInterfaces = array(); - $deprecatedInterfaces = array(); - if ($parent) { - foreach (class_implements($parent) as $interface) { - $parentInterfaces[$interface] = 1; - } - } + if ($isClass && $parent && isset(self::$finalMethods[$parent][$method->name])) { + list($declaringClass, $message) = self::$finalMethods[$parent][$method->name]; + @trigger_error(sprintf('The "%s::%s()" method is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $declaringClass, $method->name, $message, $name), E_USER_DEPRECATED); + } - foreach ($refl->getInterfaceNames() as $interface) { - if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) { - $deprecatedInterfaces[] = $interface; - } - foreach (class_implements($interface) as $interface) { - $parentInterfaces[$interface] = 1; + foreach ($parentAndTraits as $use) { + if (isset(self::$internalMethods[$use][$method->name])) { + list($declaringClass, $message) = self::$internalMethods[$use][$method->name]; + if (\strncmp($ns, $declaringClass, $len)) { + @trigger_error(sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $name), E_USER_DEPRECATED); } } + } - foreach ($deprecatedInterfaces as $interface) { - if (!isset($parentInterfaces[$interface])) { - @trigger_error(sprintf('The "%s" %s "%s" that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED); - } + // Detect method annotations + if (false === $doc = $method->getDocComment()) { + continue; + } + + foreach (array('final', 'internal') as $annotation) { + if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$)#s', $doc, $notice)) { + $message = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; + self::${$annotation.'Methods'}[$name][$method->name] = array($name, $message); } } } + + if (isset(self::$php7Reserved[\strtolower($refl->getShortName())])) { + @trigger_error(sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED); + } } if ($file) { @@ -345,8 +377,33 @@ class DebugClassLoader throw new \RuntimeException(sprintf('Case mismatch between class and real file names: "%s" vs "%s" in "%s".', substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1))); } } + } + } - return true; + /** + * `class_implements` includes interfaces from the parents so we have to manually exclude them. + * + * @param string $class + * @param string|false $parent + * + * @return string[] + */ + private function getOwnInterfaces($class, $parent) + { + $ownInterfaces = class_implements($class, false); + + if ($parent) { + foreach (class_implements($parent, false) as $interface) { + unset($ownInterfaces[$interface]); + } } + + foreach ($ownInterfaces as $interface) { + foreach (class_implements($interface) as $interface) { + unset($ownInterfaces[$interface]); + } + } + + return $ownInterfaces; } } |
