From 2cb85bda1bcf38b2d9f190531cace3c13b0b7f58 Mon Sep 17 00:00:00 2001 From: Dylan McGannon Date: Sat, 1 Sep 2018 10:30:09 +1000 Subject: [PATCH] Maintain a list of visited FQNs while following extends to avoid loops. --- fixtures/self_referencing_class.php | 22 +++++++++++++++++++--- src/DefinitionResolver.php | 6 +++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/fixtures/self_referencing_class.php b/fixtures/self_referencing_class.php index 287fc25..06dc8f0 100644 --- a/fixtures/self_referencing_class.php +++ b/fixtures/self_referencing_class.php @@ -1,4 +1,20 @@ undef_prop = 1; \ No newline at end of file +namespace RecursiveTest; + +class A extends A {} + +class B extends C {} +class C extends B {} + +class D extends E {} +class E extends F {} +class F extends D {} + +$a = new A; +$a->undef_prop = 1; + +$b = new B; +$b->undef_prop = 1; + +$d = new D; +$d->undef_prop = 1; diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 163000f..08b82aa 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -437,6 +437,7 @@ class DefinitionResolver // Find the right class that implements the member $implementorFqns = [$classFqn]; + $visitedFqns = []; while ($implementorFqn = array_shift($implementorFqns)) { // If the member FQN exists, return it @@ -449,10 +450,13 @@ class DefinitionResolver if ($implementorDef === null) { break; } + // Note the FQN as visited + $visitedFqns[] = $implementorFqn; // Repeat for parent class if ($implementorDef->extends) { foreach ($implementorDef->extends as $extends) { - if ($extends !== $implementorFqn) { + // Don't add the parent FQN if it's already been visited + if (!\in_array($extends, $visitedFqns)) { $implementorFqns[] = $extends; } }