本文目录导读:

在PHP项目中实现循环依赖检测,通常用于分析类之间的依赖关系,以下是一个完整的实现方案:
基础依赖检测类
<?php
class CircularDependencyDetector
{
private array $dependencies = [];
private array $visited = [];
private array $inStack = [];
private array $circularPaths = [];
/**
* 添加依赖关系
*/
public function addDependency(string $from, string $to): void
{
if (!isset($this->dependencies[$from])) {
$this->dependencies[$from] = [];
}
$this->dependencies[$from][] = $to;
}
/**
* 检测循环依赖
*/
public function detect(): array
{
$this->visited = [];
$this->inStack = [];
$this->circularPaths = [];
foreach (array_keys($this->dependencies) as $node) {
if (!isset($this->visited[$node])) {
$this->dfs($node, []);
}
}
return $this->circularPaths;
}
/**
* 深度优先搜索检测环
*/
private function dfs(string $node, array $path): void
{
$this->visited[$node] = true;
$this->inStack[$node] = true;
$path[] = $node;
if (isset($this->dependencies[$node])) {
foreach ($this->dependencies[$node] as $neighbor) {
if (!isset($this->visited[$neighbor])) {
$this->dfs($neighbor, $path);
} elseif (isset($this->inStack[$neighbor])) {
// 发现循环依赖
$circlePath = array_slice($path, array_search($neighbor, $path));
$circlePath[] = $neighbor;
$this->circularPaths[] = $circlePath;
}
}
}
array_pop($path);
$this->inStack[$node] = false;
}
}
反射方式检测类依赖
<?php
class ReflectionDependencyDetector
{
private array $dependencies = [];
private array $discoveredClasses = [];
/**
* 分析类的依赖关系
*/
public function analyzeClass(string $className): void
{
if (in_array($className, $this->discoveredClasses)) {
return;
}
$this->discoveredClasses[] = $className;
if (!class_exists($className)) {
return;
}
$reflection = new ReflectionClass($className);
// 分析构造函数参数
$constructor = $reflection->getConstructor();
if ($constructor) {
foreach ($constructor->getParameters() as $parameter) {
$type = $parameter->getType();
if ($type && !$type->isBuiltin()) {
$dependencyClass = $type->getName();
$this->addDependency($className, $dependencyClass);
$this->analyzeClass($dependencyClass);
}
}
}
// 分析属性类型
foreach ($reflection->getProperties() as $property) {
$type = $property->getType();
if ($type && !$type->isBuiltin()) {
$dependencyClass = $type->getName();
$this->addDependency($className, $dependencyClass);
$this->analyzeClass($dependencyClass);
}
}
}
public function addDependency(string $from, string $to): void
{
if (!isset($this->dependencies[$from])) {
$this->dependencies[$from] = [];
}
$this->dependencies[$from][] = $to;
}
public function getDependencies(): array
{
return $this->dependencies;
}
/**
* 检测所有依赖中的循环
*/
public function detectCircular(): array
{
$detector = new CircularDependencyDetector();
foreach ($this->dependencies as $from => $tos) {
foreach ($tos as $to) {
$detector->addDependency($from, $to);
}
}
return $detector->detect();
}
}
文件扫描方式实现
<?php
class FileDependencyAnalyzer
{
private string $basePath;
private array $classMap = [];
public function __construct(string $basePath)
{
$this->basePath = rtrim($basePath, '/');
}
/**
* 扫描目录下的PHP文件
*/
public function scanDirectory(string $dir = ''): void
{
$targetDir = $dir ? $this->basePath . '/' . $dir : $this->basePath;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($targetDir)
);
foreach ($iterator as $file) {
if ($file->getExtension() === 'php') {
$this->analyzeFile($file->getPathname());
}
}
}
/**
* 分析单个文件
*/
private function analyzeFile(string $filePath): void
{
$content = file_get_contents($filePath);
// 提取类名
preg_match('/class\s+(\w+)/', $content, $matches);
if (!isset($matches[1])) {
return;
}
$className = $matches[1];
// 提取use语句
preg_match_all('/use\s+([^;]+);/', $content, $useMatches);
// 提取方法参数类型
preg_match_all('/function\s+\w+\s*\([^)]*\)/', $content, $methodMatches);
$dependencies = [];
// 从use语句中提取依赖
foreach ($useMatches[1] ?? [] as $use) {
$parts = explode(' as ', $use);
$fullClass = trim($parts[0]);
$dependencies[] = $this->extractClassName($fullClass);
}
// 从方法参数中提取依赖
foreach ($methodMatches[0] ?? [] as $method) {
preg_match_all('/(\w+)\s+\$\w+/', $method, $paramMatches);
foreach ($paramMatches[1] ?? [] as $typeHint) {
if (!in_array($typeHint, ['string', 'int', 'float', 'bool', 'array', 'callable', 'iterable', 'object', 'mixed', 'void', 'null', 'self', 'parent'])) {
$dependencies[] = $typeHint;
}
}
}
$this->classMap[$className] = array_unique($dependencies);
}
/**
* 提取类名(不包括命名空间)
*/
private function extractClassName(string $fullClassName): string
{
$parts = explode('\\', $fullClassName);
return end($parts);
}
/**
* 检测循环依赖
*/
public function detectCircularDependencies(): array
{
$detector = new CircularDependencyDetector();
foreach ($this->classMap as $className => $dependencies) {
foreach ($dependencies as $dependency) {
if (isset($this->classMap[$dependency])) {
$detector->addDependency($className, $dependency);
}
}
}
return $detector->detect();
}
}
使用示例
<?php
// 示例1:手动添加依赖检测
$detector = new CircularDependencyDetector();
$detector->addDependency('ClassA', 'ClassB');
$detector->addDependency('ClassB', 'ClassC');
$detector->addDependency('ClassC', 'ClassA'); // 创建循环依赖
$results = $detector->detect();
echo "循环依赖检测结果:" . PHP_EOL;
foreach ($results as $path) {
echo implode(' -> ', $path) . PHP_EOL;
}
// 示例2:使用反射检测
$reflector = new ReflectionDependencyDetector();
$reflector->analyzeClass('SomeClass');
$circular = $reflector->detectCircular();
// 示例3:文件扫描检测
$fileAnalyzer = new FileDependencyAnalyzer('/path/to/your/project');
$fileAnalyzer->scanDirectory('src');
$circularDeps = $fileAnalyzer->detectCircularDependencies();
// 输出结果
if (!empty($circularDeps)) {
echo "发现循环依赖:" . PHP_EOL;
foreach ($circularDeps as $index => $path) {
echo "循环 #" . ($index + 1) . ": " . implode(' -> ', $path) . PHP_EOL;
}
} else {
echo "未发现循环依赖" . PHP_EOL;
}
Composer包集成方式
如果需要更强大的循环依赖检测,可以使用Composer依赖:
composer require --dev phpmd/phpmd
然后在项目配置中包含循环依赖检测规则。
这样的实现可以:
- 检测类之间的循环依赖
- 支持反射分析和文件扫描
- 输出完整的循环依赖路径
- 轻量级,无需额外依赖
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播