Test Failed
Push — main ( 3d89fd...8d1023 )
by Chema
03:11
created

DependencyTreeAnalyzer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 0
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Container;
6
7
use ReflectionClass;
8
use ReflectionNamedType;
9
10
use function class_exists;
11
12
/**
13
 * Analyzes and reports dependency trees for classes.
14
 */
15
final class DependencyTreeAnalyzer
16
{
17
    public function __construct(
18
        private BindingResolver $bindingResolver,
19
    ) {
20
    }
21
22
    /**
23
     * Get all dependencies for a class as a flat list.
24
     *
25
     * @param class-string $className
26
     *
27
     * @return list<string>
28
     */
29
    public function analyze(string $className): array
30
    {
31
        if (!class_exists($className)) {
32
            return [];
33
        }
34
35
        $dependencies = [];
36
        $this->collectDependencies($className, $dependencies);
37
38
        /** @var list<string> */
39
        return array_keys($dependencies);
40
    }
41
42
    /**
43
     * Recursively collect dependencies for a class.
44
     *
45
     * @param class-string $className
46
     * @param array<string, true> $dependencies
47
     */
48
    private function collectDependencies(string $className, array &$dependencies): void
49
    {
50
        $reflection = new ReflectionClass($className);
51
52
        $constructor = $reflection->getConstructor();
53
        if ($constructor === null) {
54
            return;
55
        }
56
57
        foreach ($constructor->getParameters() as $parameter) {
58
            $type = $parameter->getType();
59
            if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) {
60
                continue;
61
            }
62
63
            /** @var class-string $paramTypeName */
64
            $paramTypeName = $type->getName();
65
66
            // Resolve binding if it's an interface
67
            $paramTypeName = $this->bindingResolver->resolveType($paramTypeName);
68
69
            if (isset($dependencies[$paramTypeName])) {
70
                continue; // Already processed
71
            }
72
73
            $dependencies[$paramTypeName] = true;
74
75
            if (class_exists($paramTypeName)) {
76
                $this->collectDependencies($paramTypeName, $dependencies);
77
            }
78
        }
79
    }
80
}
81