Skip to content

Commit

Permalink
Broke out the class name detection to make it easier to test
Browse files Browse the repository at this point in the history
  • Loading branch information
gsherwood committed Oct 1, 2020
1 parent 1de501b commit 95e69ac
Showing 1 changed file with 43 additions and 17 deletions.
60 changes: 43 additions & 17 deletions autoload.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,27 +160,55 @@ 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) {
return array_diff($remaining, class_parents($current));
},
$newClasses
);

foreach ($newClasses as $name) {
if (isset(self::$loadedFiles[$name]) === false) {
$className = $name;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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()


/**
Expand Down

0 comments on commit 95e69ac

Please sign in to comment.