-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path11-dependency-analyzer.php
More file actions
101 lines (87 loc) · 4.51 KB
/
11-dependency-analyzer.php
File metadata and controls
101 lines (87 loc) · 4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<?php
declare(strict_types=1);
/**
* Example 11: DependencyAnalyzer + CircularDetector.
*
* Demonstrates:
* - DependencyAnalyzer::buildGraph() — builds dependency graph from scan results
* - DependencyAnalyzer::detectCircularDependencies() — Tarjan-based cycle detection
* - CircularDetector::check() — high-level wrapper with optional exception throwing
*
* Requires ReflectionScanner (constructors and type hints need reflection).
*
* !! PARAMETER REFERENCE (confirmed from implementations):
*
* DependencyAnalyzer::buildGraph(result: DiscoveryResult): DependencyGraph
* - Builds directed graph: FQCN → list of direct dependencies
* - Dependencies resolved from constructor param type hints (ReflectionScanner)
*
* DependencyAnalyzer::detectCircularDependencies(graph: DependencyGraph): string[][]
* - Tarjan SCC algorithm; returns list of cycles (each cycle is a list of FQCNs)
*
* CircularDetector::check(dirs: string[], throw: bool):
* - throw = true → throws CircularDependencyException on first cycle found
* - throw = false → returns list of cycle descriptions as strings
*/
require_once __DIR__ . '/../vendor/autoload.php';
use KaririCode\ClassDiscovery\Analyzer\CircularDetector;
use KaririCode\ClassDiscovery\Analyzer\DependencyAnalyzer;
use KaririCode\ClassDiscovery\Scanner\ComposerNamespaceResolver;
use KaririCode\ClassDiscovery\Scanner\ReflectionScanner;
echo "\n";
echo "╔══════════════════════════════════════════════════════════╗\n";
echo "║ Example 11: DependencyAnalyzer + CircularDetector ║\n";
echo "╚══════════════════════════════════════════════════════════╝\n\n";
$resolver = new ComposerNamespaceResolver(
composerJsonPath: __DIR__ . '/../composer.json',
);
// ReflectionScanner: populates constructor params, interfaces, traits
$scanner = new ReflectionScanner($resolver);
$result = $scanner->scan([__DIR__ . '/../src']);
echo "📦 Scan result: " . count($result) . " class(es)\n\n";
// ── DependencyAnalyzer: build dependency graph ───────────────────
$analyzer = new DependencyAnalyzer();
$graph = $analyzer->buildGraph($result);
echo "── Dependency Graph ───────────────────────────────────────\n";
foreach ($graph as $class => $deps) {
$shortClass = substr($class, strrpos($class, '\\') + 1);
if ($deps === []) {
echo " {$shortClass} → (no dependencies)\n";
} else {
$shortDeps = array_map(
static fn (string $d): string => substr($d, strrpos($d, '\\') + 1),
$deps,
);
echo " {$shortClass} → " . implode(', ', $shortDeps) . "\n";
}
}
// ── DependencyAnalyzer: detect circular dependencies ────────────
echo "\n── Circular Dependency Detection ──────────────────────────\n";
$cycles = $analyzer->detectCircularDependencies($graph);
if ($cycles === []) {
echo " ✅ No circular dependencies detected.\n";
} else {
echo " ⚠ Circular dependency cycle(s) found:\n";
foreach ($cycles as $cycle) {
$shortCycle = array_map(
static fn (string $c): string => substr($c, strrpos($c, '\\') + 1),
$cycle,
);
echo " → " . implode(' → ', $shortCycle) . "\n";
}
}
// ── CircularDetector: high-level wrapper (no throw) ─────────────
echo "\n── CircularDetector (throwOnDetection=false) ──────────────\n";
$detector = new CircularDetector($analyzer, throwOnDetection: false);
$detectedCycles = $detector->check($result);
echo " Cycles detected: " . count($detectedCycles) . "\n";
// ── CircularDetector: high-level wrapper (throw on detection) ───
echo "\n── CircularDetector (throwOnDetection=true) ───────────────\n";
try {
$strictDetector = new CircularDetector($analyzer, throwOnDetection: true);
$strictDetector->check($result);
echo " ✅ No cycles — exception NOT thrown.\n";
} catch (\KaririCode\ClassDiscovery\Exception\DiscoveryException $e) {
echo " ⚠ Exception thrown: " . $e->getMessage() . "\n";
}
echo "\n ✅ DependencyAnalyzer + CircularDetector: OK\n\n";