Skip to content

Commit e1abbae

Browse files
committed
Replace recursion with parent iterations in fetchers
1 parent 9be4cdd commit e1abbae

7 files changed

+63
-78
lines changed

src/Aspect/InvariantCheckerAspect.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class InvariantCheckerAspect extends AbstractContractAspect implements Aspect
2929
public function __construct(Reader $reader)
3030
{
3131
parent::__construct($reader);
32-
$this->invariantFetcher = new InvariantFetcher(Invariant::class);
32+
$this->invariantFetcher = new InvariantFetcher(Invariant::class, $reader);
3333
}
3434

3535
/**
@@ -65,7 +65,7 @@ public function invariantContract(MethodInvocation $invocation)
6565
*/
6666
private function fetchAllContracts(ReflectionClass $class)
6767
{
68-
$allContracts = $this->invariantFetcher->getConditions($class, $this->reader);
68+
$allContracts = $this->invariantFetcher->getConditions($class);
6969
foreach ($this->reader->getClassAnnotations($class) as $annotation) {
7070
if ($annotation instanceof Invariant) {
7171
$allContracts[] = $annotation;

src/Aspect/PostconditionCheckerAspect.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class PostconditionCheckerAspect extends AbstractContractAspect implements Aspec
2828
public function __construct(Reader $reader)
2929
{
3030
parent::__construct($reader);
31-
$this->methodConditionFetcher = new MethodConditionFetcher(Ensure::class);
31+
$this->methodConditionFetcher = new MethodConditionFetcher(Ensure::class, $reader);
3232
}
3333

3434
/**
@@ -82,7 +82,6 @@ private function fetchParentsContracts(MethodInvocation $invocation)
8282
{
8383
return $this->methodConditionFetcher->getConditions(
8484
$invocation->getMethod()->getDeclaringClass(),
85-
$this->reader,
8685
$invocation->getMethod()->name
8786
);
8887
}

src/Aspect/PreconditionCheckerAspect.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class PreconditionCheckerAspect extends AbstractContractAspect implements Aspect
2828
public function __construct(Reader $reader)
2929
{
3030
parent::__construct($reader);
31-
$this->methodConditionFetcher = new MethodConditionWithInheritDocFetcher(Verify::class);
31+
$this->methodConditionFetcher = new MethodConditionWithInheritDocFetcher(Verify::class, $reader);
3232
}
3333

3434
/**
@@ -74,7 +74,6 @@ private function fetchParentsContracts(MethodInvocation $invocation)
7474
{
7575
return $this->methodConditionFetcher->getConditions(
7676
$invocation->getMethod()->getDeclaringClass(),
77-
$this->reader,
7877
$invocation->getMethod()->name
7978
);
8079
}

src/Contract/Fetcher/ParentClass/Fetcher.php src/Contract/Fetcher/ParentClass/AbstractFetcher.php

+15-4
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,42 @@
1010

1111
namespace PhpDeal\Contract\Fetcher\ParentClass;
1212

13-
class Fetcher
13+
use Doctrine\Common\Annotations\Reader;
14+
15+
abstract class AbstractFetcher
1416
{
1517
/**
1618
* @var string
1719
*/
1820
protected $expectedAnnotationType;
1921

22+
/**
23+
* @var Reader
24+
*/
25+
protected $annotationReader;
26+
2027
/**
2128
* @param string $expectedAnnotationType
29+
* @param Reader $reader
2230
*/
23-
public function __construct($expectedAnnotationType)
31+
public function __construct($expectedAnnotationType, Reader $reader)
2432
{
2533
$this->expectedAnnotationType = $expectedAnnotationType;
34+
$this->annotationReader = $reader;
2635
}
2736

2837
/**
38+
* Performs filtering of annotations by the requested class name
39+
*
2940
* @param array $annotations
3041
* @return array
3142
*/
32-
protected function getContractAnnotations(array $annotations)
43+
protected function filterContractAnnotation(array $annotations)
3344
{
3445
$contractAnnotations = [];
3546

3647
foreach ($annotations as $annotation) {
37-
if (is_a($annotation, $this->expectedAnnotationType)) {
48+
if ($annotation instanceof $this->expectedAnnotationType) {
3849
$contractAnnotations[] = $annotation;
3950
}
4051
}

src/Contract/Fetcher/ParentClass/InvariantFetcher.php

+14-13
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,30 @@
1010

1111
namespace PhpDeal\Contract\Fetcher\ParentClass;
1212

13-
use Doctrine\Common\Annotations\Reader;
1413
use ReflectionClass;
1514

16-
class InvariantFetcher extends Fetcher
15+
class InvariantFetcher extends AbstractFetcher
1716
{
1817
/**
18+
* Fetches conditions from all parent classes recursively
19+
*
1920
* @param ReflectionClass $class
20-
* @param Reader $reader
21-
* @param array $contracts
21+
*
2222
* @return array
2323
*/
24-
public function getConditions(ReflectionClass $class, Reader $reader, array $contracts = [])
24+
public function getConditions(ReflectionClass $class)
2525
{
26-
$parentClass = $class->getParentClass();
27-
28-
if (!$parentClass) {
29-
return $contracts;
26+
$annotations = [];
27+
$parentClasses = [];
28+
while ($class = $class->getParentClass()) {
29+
$parentClasses[] = $class;
3030
}
3131

32-
$annotations = $reader->getClassAnnotations($parentClass);
33-
$contractAnnotations = $this->getContractAnnotations($annotations);
34-
$contracts = array_merge($contracts, $contractAnnotations);
32+
foreach ($parentClasses as $parentClass) {
33+
$annotations = array_merge($annotations, $this->annotationReader->getClassAnnotations($parentClass));
34+
}
35+
$contracts = $this->filterContractAnnotation($annotations);
3536

36-
return $this->getConditions($parentClass, $reader, $contracts);
37+
return $contracts;
3738
}
3839
}

src/Contract/Fetcher/ParentClass/MethodConditionFetcher.php

+14-14
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,31 @@
1010

1111
namespace PhpDeal\Contract\Fetcher\ParentClass;
1212

13-
use Doctrine\Common\Annotations\Reader;
1413
use ReflectionClass;
1514

16-
class MethodConditionFetcher extends Fetcher
15+
class MethodConditionFetcher extends AbstractFetcher
1716
{
1817
/**
18+
* Fetches conditions from all parent method prototypes recursively
19+
*
1920
* @param ReflectionClass $class
20-
* @param Reader $reader
2121
* @param string $methodName
22-
* @param array $contracts
22+
*
2323
* @return array
2424
*/
25-
public function getConditions(ReflectionClass $class, Reader $reader, $methodName, array $contracts = [])
25+
public function getConditions(ReflectionClass $class, $methodName)
2626
{
27-
$parentClass = $class->getParentClass();
28-
29-
if (!$parentClass) {
30-
return $contracts;
27+
$annotations = [];
28+
$parentMethods = [];
29+
while (($class = $class->getParentClass()) && $class->hasMethod($methodName)) {
30+
$parentMethods[] = $class->getMethod($methodName);
3131
}
3232

33-
$parentMethod = $parentClass->getMethod($methodName);
34-
$annotations = $reader->getMethodAnnotations($parentMethod);
35-
$contractAnnotations = $this->getContractAnnotations($annotations);
36-
$contracts = array_merge($contracts, $contractAnnotations);
33+
foreach ($parentMethods as $parentMethod) {
34+
$annotations = array_merge($annotations, $this->annotationReader->getMethodAnnotations($parentMethod));
35+
}
36+
$contracts = $this->filterContractAnnotation($annotations);
3737

38-
return $this->getConditions($parentClass, $reader, $methodName, $contracts);
38+
return $contracts;
3939
}
4040
}

src/Contract/Fetcher/ParentClass/MethodConditionWithInheritDocFetcher.php

+16-41
Original file line numberDiff line numberDiff line change
@@ -10,60 +10,35 @@
1010

1111
namespace PhpDeal\Contract\Fetcher\ParentClass;
1212

13-
use Doctrine\Common\Annotations\Reader;
1413
use ReflectionClass;
15-
use ReflectionMethod;
1614

17-
class MethodConditionWithInheritDocFetcher extends Fetcher
15+
class MethodConditionWithInheritDocFetcher extends AbstractFetcher
1816
{
1917
/**
18+
* Fetches conditions from all parent method prototypes recursively
19+
*
2020
* @param ReflectionClass $class
21-
* @param Reader $reader
2221
* @param string $methodName
23-
* @param array $contracts
22+
*
2423
* @return array
2524
*/
26-
public function getConditions(ReflectionClass $class, Reader $reader, $methodName, array $contracts = [])
25+
public function getConditions(ReflectionClass $class, $methodName)
2726
{
28-
if ($this->hasInheritDoc($class->getMethod($methodName))) {
29-
return $this->getConditionsWithInheritDoc($class, $reader, $methodName, $contracts);
27+
$annotations = [];
28+
$parentMethods = [];
29+
while (
30+
preg_match('/\@inheritdoc/i', $class->getMethod($methodName)->getDocComment())
31+
&& ($class = $class->getParentClass())
32+
&& $class->hasMethod($methodName)
33+
) {
34+
$parentMethods[] = $class->getMethod($methodName);
3035
}
3136

32-
return $contracts;
33-
}
34-
35-
/**
36-
* @param ReflectionClass $class
37-
* @param Reader $reader
38-
* @param string $methodName
39-
* @param array $contracts
40-
* @return array
41-
*/
42-
private function getConditionsWithInheritDoc(ReflectionClass $class, Reader $reader, $methodName, array $contracts)
43-
{
44-
$parentClass = $class->getParentClass();
45-
if (!$parentClass) {
46-
return $contracts;
47-
}
48-
49-
$parentMethod = $parentClass->getMethod($methodName);
50-
$annotations = $reader->getMethodAnnotations($parentMethod);
51-
$contractAnnotations = $this->getContractAnnotations($annotations);
52-
$contracts = array_merge($contracts, $contractAnnotations);
53-
54-
if ($this->hasInheritDoc($parentMethod)) {
55-
return $this->getConditionsWithInheritDoc($parentClass, $reader, $methodName, $contracts);
37+
foreach ($parentMethods as $parentMethod) {
38+
$annotations = array_merge($annotations, $this->annotationReader->getMethodAnnotations($parentMethod));
5639
}
40+
$contracts = $this->filterContractAnnotation($annotations);
5741

5842
return $contracts;
5943
}
60-
61-
/**
62-
* @param ReflectionMethod $method
63-
* @return bool
64-
*/
65-
private function hasInheritDoc(ReflectionMethod $method)
66-
{
67-
return preg_match('/\@inheritdoc/i', $method->getDocComment()) > 0;
68-
}
6944
}

0 commit comments

Comments
 (0)