From 95e69ac528c1fd3294a922c60fe6b889d5cdfad1 Mon Sep 17 00:00:00 2001 From: Greg Sherwood Date: Thu, 1 Oct 2020 13:05:51 +1000 Subject: [PATCH] Broke out the class name detection to make it easier to test --- autoload.php | 60 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/autoload.php b/autoload.php index 0690b75cd0..1691d7e8de 100644 --- a/autoload.php +++ b/autoload.php @@ -160,20 +160,47 @@ public static function loadFile($path) return self::$loadedClasses[$path]; } - $classes = get_declared_classes(); - $interfaces = get_declared_interfaces(); - $traits = get_declared_traits(); + $classesBeforeLoad = [ + 'classes' => get_declared_classes(), + 'interfaces' => get_declared_interfaces(), + 'traits' => get_declared_traits(), + ]; include $path; - $className = null; - $newClasses = array_reverse(array_diff(get_declared_classes(), $classes)); - // Since PHP 7.4 get_declared_classes() does not guarantee any order. That - // implies that parent classes aren't the first any more, rendering the - // array_reverse() technique futile for the loop & break code that follows. - // So, additionally, let's try to reduce the list of candidates by removing all - // the classes known to be "parents". That way, at the end, only the "main" - // class just included with remain. + $classesAfterLoad = [ + 'classes' => get_declared_classes(), + 'interfaces' => get_declared_interfaces(), + 'traits' => get_declared_traits(), + ]; + + $className = self::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); + + self::$loadedClasses[$path] = $className; + self::$loadedFiles[$className] = $path; + return self::$loadedClasses[$path]; + + }//end loadFile() + + + /** + * Determine which class was loaded based on the before and after lists of loaded classes. + * + * @param array $classesBeforeLoad The classes/interfaces/traits before the file was included. + * @param array $classesAfterLoad The classes/interfaces/traits after the file was included. + * + * @return string The fully qualified name of the class in the loaded file. + */ + public static function determineLoadedClass($classesBeforeLoad, $classesAfterLoad) + { + $className = null; + + $newClasses = array_diff($classesAfterLoad['classes'], $classesBeforeLoad['classes']); + + // Since PHP 7.4 get_declared_classes() does not guarantee any order, making + // it impossible to use order to determine which is the parent an which is the child. + // Let's reduce the list of candidates by removing all the classes known to be "parents". + // That way, at the end, only the "main" class just included will remain. $newClasses = array_reduce( $newClasses, function ($remaining, $current) { @@ -181,6 +208,7 @@ function ($remaining, $current) { }, $newClasses ); + foreach ($newClasses as $name) { if (isset(self::$loadedFiles[$name]) === false) { $className = $name; @@ -189,7 +217,7 @@ function ($remaining, $current) { } if ($className === null) { - $newClasses = array_reverse(array_diff(get_declared_interfaces(), $interfaces)); + $newClasses = array_reverse(array_diff($classesAfterLoad['interfaces'], $classesBeforeLoad['interfaces'])); foreach ($newClasses as $name) { if (isset(self::$loadedFiles[$name]) === false) { $className = $name; @@ -199,7 +227,7 @@ function ($remaining, $current) { } if ($className === null) { - $newClasses = array_reverse(array_diff(get_declared_traits(), $traits)); + $newClasses = array_reverse(array_diff($classesAfterLoad['traits'], $classesBeforeLoad['traits'])); foreach ($newClasses as $name) { if (isset(self::$loadedFiles[$name]) === false) { $className = $name; @@ -208,11 +236,9 @@ function ($remaining, $current) { } } - self::$loadedClasses[$path] = $className; - self::$loadedFiles[$className] = $path; - return self::$loadedClasses[$path]; + return $className; - }//end loadFile() + }//end determineLoadedClass() /**