in doc-architect/doc-architect-core/src/main/java/com/docarchitect/core/scanner/impl/php/PhpInternalDependencyScanner.java [255:338]
private void scanPhpFile(Path file, ScanContext context, List<Component> components,
List<Relationship> relationships, Set<String> processedClasses) throws IOException {
String content = readFileContent(file);
// Extract namespace
String namespace = extractNamespace(content);
// Build import map for resolving short class names
Map<String, String> imports = buildImportMap(content);
// Extract class definition
Matcher classMatcher = findFirst(CLASS_DEFINITION_PATTERN, content);
if (classMatcher == null) {
return; // Not a class file
}
String classType = classMatcher.group(1); // class, interface, or trait
String className = classMatcher.group(2);
String extendsClause = classMatcher.group(3);
String implementsClause = classMatcher.group(4);
String fullyQualifiedName = buildFullyQualifiedName(namespace, className);
// Skip if already processed
if (processedClasses.contains(fullyQualifiedName)) {
return;
}
processedClasses.add(fullyQualifiedName);
// Create component
Component component = createComponent(fullyQualifiedName, className, classType, file, context);
components.add(component);
// Extract dependencies
// 1. Use statement imports (but only track the ones that are actually used)
for (Map.Entry<String, String> importEntry : imports.entrySet()) {
String importedClass = importEntry.getValue();
// Only add import relationship if the imported class is used in the file
// beyond just the use statement itself
String shortName = importEntry.getKey();
if (isClassUsed(content, shortName, importedClass)) {
relationships.add(createRelationship(
fullyQualifiedName, importedClass, DEPENDENCY_TYPE_IMPORT,
"Imports " + importedClass
));
}
}
// 2. Class inheritance
if (extendsClause != null && !extendsClause.isBlank()) {
String parentClass = resolveClassName(extendsClause.trim(), namespace, imports);
relationships.add(createRelationship(
fullyQualifiedName, parentClass, DEPENDENCY_TYPE_INHERITANCE,
"Extends " + parentClass
));
}
// 3. Interface implementations
if (implementsClause != null && !implementsClause.isBlank()) {
for (String interfaceName : implementsClause.split(",")) {
String trimmed = interfaceName.trim();
if (!trimmed.isEmpty()) {
String resolvedInterface = resolveClassName(trimmed, namespace, imports);
relationships.add(createRelationship(
fullyQualifiedName, resolvedInterface, DEPENDENCY_TYPE_INTERFACE,
"Implements " + resolvedInterface
));
}
}
}
// 4. Trait usage
extractTraitDependencies(content, fullyQualifiedName, namespace, imports, relationships);
// 5. Constructor injection
extractConstructorDependencies(content, fullyQualifiedName, namespace, imports, relationships);
// 6. Method injection (setter injection)
extractMethodInjectionDependencies(content, fullyQualifiedName, namespace, imports, relationships);
// 7. Laravel container bindings
extractContainerBindings(content, fullyQualifiedName, namespace, imports, relationships);
}