Backup #878
| ID | 878 |
| Dateipfad | /var/www/dev.campus.systemische-tools.de/src/Infrastructure/CodeAnalysis/PhpFileParser.php |
| Version | 1 |
| Typ |
modified |
| Größe | 6.6 KB |
| Hash | 242080786579e14796dae0cf7c6c46cbefe690d41529f10a445bc359c643ccac |
| Datum | 2025-12-23 14:14:46 |
| Geändert von | claude-code-hook |
| Grund | Claude Code Pre-Hook Backup vor Write-Operation |
| Datei existiert |
Ja
|
Dateiinhalt
<?php
declare(strict_types=1);
namespace Infrastructure\CodeAnalysis;
// @responsibility: Tokenizer-basierte PHP-Dateianalyse
final class PhpFileParser
{
/**
* Parst eine PHP-Datei und extrahiert Metadaten.
*
* @return array{
* namespace: string|null,
* classes: array<array{name: string, type: string, line: int}>,
* functions: array<array{name: string, visibility: string|null, line: int}>,
* error: string|null
* }
*/
public function parse(string $filePath): array
{
$result = [
'namespace' => null,
'classes' => [],
'functions' => [],
'error' => null,
];
if (!file_exists($filePath) || !is_readable($filePath)) {
$result['error'] = 'Datei nicht lesbar';
return $result;
}
$content = file_get_contents($filePath);
if ($content === false) {
$result['error'] = 'Datei konnte nicht gelesen werden';
return $result;
}
try {
$tokens = @token_get_all($content);
} catch (\Throwable $e) {
$result['error'] = 'Token-Fehler: ' . $e->getMessage();
return $result;
}
$result['namespace'] = $this->extractNamespace($tokens);
$result['classes'] = $this->extractClasses($tokens);
$result['functions'] = $this->extractFunctions($tokens);
return $result;
}
/**
* @param array<mixed> $tokens
*/
private function extractNamespace(array $tokens): ?string
{
$namespace = '';
$capturing = false;
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] === T_NAMESPACE) {
$capturing = true;
continue;
}
if ($capturing) {
if ($token[0] === T_NAME_QUALIFIED || $token[0] === T_STRING) {
$namespace .= $token[1];
} elseif ($token[0] === T_NS_SEPARATOR) {
$namespace .= '\\';
}
}
} elseif ($capturing && ($token === ';' || $token === '{')) {
break;
}
}
return $namespace !== '' ? $namespace : null;
}
/**
* @param array<mixed> $tokens
* @return array<array{name: string, type: string, line: int}>
*/
private function extractClasses(array $tokens): array
{
$classes = [];
$count = count($tokens);
for ($i = 0; $i < $count; $i++) {
$token = $tokens[$i];
if (!is_array($token)) {
continue;
}
$type = match ($token[0]) {
T_CLASS => 'class',
T_INTERFACE => 'interface',
T_TRAIT => 'trait',
T_ENUM => 'enum',
default => null,
};
if ($type === null) {
continue;
}
// Prüfen ob es kein anonymes Class-Statement ist
$prevIndex = $this->findPrevNonWhitespace($tokens, $i);
if ($prevIndex !== null && is_array($tokens[$prevIndex]) && $tokens[$prevIndex][0] === T_NEW) {
continue;
}
// Klassennamen finden
for ($j = $i + 1; $j < $count; $j++) {
if (is_array($tokens[$j]) && $tokens[$j][0] === T_STRING) {
$classes[] = [
'name' => $tokens[$j][1],
'type' => $type,
'line' => $token[2],
];
break;
}
}
}
return $classes;
}
/**
* @param array<mixed> $tokens
* @return array<array{name: string, visibility: string|null, line: int}>
*/
private function extractFunctions(array $tokens): array
{
$functions = [];
$count = count($tokens);
$braceDepth = 0;
$inClass = false;
for ($i = 0; $i < $count; $i++) {
$token = $tokens[$i];
if (!is_array($token)) {
if ($token === '{') {
$braceDepth++;
} elseif ($token === '}') {
$braceDepth--;
if ($braceDepth === 0) {
$inClass = false;
}
}
continue;
}
// Klasse/Interface/Trait betreten
if (in_array($token[0], [T_CLASS, T_INTERFACE, T_TRAIT, T_ENUM], true)) {
$inClass = true;
}
if ($token[0] !== T_FUNCTION) {
continue;
}
// Visibility ermitteln
$visibility = null;
if ($inClass) {
for ($j = $i - 1; $j >= 0; $j--) {
if (!is_array($tokens[$j])) {
break;
}
if ($tokens[$j][0] === T_PUBLIC) {
$visibility = 'public';
break;
}
if ($tokens[$j][0] === T_PROTECTED) {
$visibility = 'protected';
break;
}
if ($tokens[$j][0] === T_PRIVATE) {
$visibility = 'private';
break;
}
if ($tokens[$j][0] !== T_WHITESPACE && $tokens[$j][0] !== T_STATIC && $tokens[$j][0] !== T_FINAL && $tokens[$j][0] !== T_ABSTRACT) {
break;
}
}
}
// Funktionsnamen finden
for ($j = $i + 1; $j < $count; $j++) {
if (is_array($tokens[$j]) && $tokens[$j][0] === T_STRING) {
$functions[] = [
'name' => $tokens[$j][1],
'visibility' => $visibility,
'line' => $token[2],
];
break;
}
// Anonyme Funktion (kein Name)
if ($tokens[$j] === '(') {
break;
}
}
}
return $functions;
}
/**
* @param array<mixed> $tokens
*/
private function findPrevNonWhitespace(array $tokens, int $index): ?int
{
for ($i = $index - 1; $i >= 0; $i--) {
if (!is_array($tokens[$i]) || $tokens[$i][0] !== T_WHITESPACE) {
return $i;
}
}
return null;
}
}
Vollständig herunterladen
Aktionen
Andere Versionen dieser Datei
| ID |
Version |
Typ |
Größe |
Datum |
| 2021 |
12 |
modified |
8.0 KB |
2025-12-28 23:20 |
| 1039 |
11 |
modified |
11.7 KB |
2025-12-25 01:51 |
| 1038 |
10 |
modified |
11.7 KB |
2025-12-25 01:51 |
| 1037 |
9 |
modified |
15.2 KB |
2025-12-25 01:50 |
| 1036 |
8 |
modified |
15.2 KB |
2025-12-25 01:50 |
| 1034 |
7 |
modified |
18.9 KB |
2025-12-25 01:48 |
| 1033 |
6 |
modified |
18.8 KB |
2025-12-25 01:48 |
| 1032 |
5 |
modified |
20.9 KB |
2025-12-25 01:45 |
| 1031 |
4 |
modified |
20.9 KB |
2025-12-25 01:44 |
| 1028 |
3 |
modified |
20.9 KB |
2025-12-25 00:18 |
| 1027 |
2 |
modified |
20.9 KB |
2025-12-25 00:17 |
| 878 |
1 |
modified |
6.6 KB |
2025-12-23 14:14 |
← Zurück zur Übersicht