Quelltext des aktuellen Standes
<?php
declare(strict_types=1);
/**
* Deckt ab, dass jede verwendete PHP-Kernkonstante auch existiert.
*
* Ein vertippter Konstantenname fällt beim Lesen nicht auf und beim Start
* nicht ebenfalls – er schlägt erst zu, wenn genau die Zeile ausgeführt wird,
* und dann als Abbruch mit internem Fehler. Geprüft werden nur Konstanten aus
* dem PHP-Kern, die auf jeder Installation vorhanden sind; Konstanten aus
* optionalen Erweiterungen bleiben außen vor.
*/
return static function (): void {
/** Präfixe, deren Konstanten der PHP-Kern immer mitbringt. */
$praefixe = ['LIBXML_', 'JSON_', 'PREG_', 'ENT_', 'PATHINFO_', 'UPLOAD_ERR_',
'FILTER_', 'SORT_', 'STR_PAD_', 'ARRAY_FILTER_', 'COUNT_', 'SEEK_', 'LOCK_'];
/** Sammelt alle als Konstante gelesenen Bezeichner einer Datei. */
$konstantenIn = static function (string $datei) use ($praefixe): array {
$tokens = @token_get_all((string)file_get_contents($datei));
$namen = [];
$vorher = null;
foreach ($tokens as $t) {
if (is_array($t) && in_array($t[0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], true)) {
continue;
}
if (is_array($t) && $t[0] === T_STRING) {
$name = $t[1];
// Eigenschafts- und Klassenzugriffe sind keine Konstanten.
$istZugriff = is_array($vorher)
&& in_array($vorher[0], [T_OBJECT_OPERATOR, T_DOUBLE_COLON, T_FUNCTION, T_NEW, T_CONST], true);
if (!$istZugriff) {
foreach ($praefixe as $p) {
if (str_starts_with($name, $p)) {
$namen[$name] = true;
break;
}
}
}
}
$vorher = $t;
}
return array_keys($namen);
};
/** Alle PHP-Dateien des Projekts (ohne Fremdcode). */
$dateien = static function (): array {
$wurzel = dirname(__DIR__);
$liste = [];
foreach (['src', 'bin', 'public', 'templates'] as $ordner) {
$pfad = $wurzel . '/' . $ordner;
if (!is_dir($pfad)) {
continue;
}
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pfad));
foreach ($it as $f) {
if ($f->isFile() && $f->getExtension() === 'php') {
$liste[] = $f->getPathname();
}
}
}
return $liste;
};
test('Jede verwendete PHP-Kernkonstante existiert', function () use ($dateien, $konstantenIn) {
$fehlend = [];
foreach ($dateien() as $datei) {
foreach ($konstantenIn($datei) as $name) {
if (!defined($name)) {
$fehlend[] = str_replace(dirname(__DIR__) . '/', '', $datei) . ': ' . $name;
}
}
}
assertSame([], $fehlend, "Unbekannte Konstante(n):\n " . implode("\n ", $fehlend));
});
test('Der Netzwerkplan prueft das XML mit einer echten Konstante', function () {
// Ein unbekannter Name würde hier erst beim Hochladen auffallen.
$quelle = (string)file_get_contents(__DIR__ . '/../src/Controllers/NetworkDiagramController.php');
assertTrue(str_contains($quelle, 'LIBXML_NONET | LIBXML_NOERROR'),
'Die Kennzeichen für die XML-Prüfung stimmen nicht');
assertFalse(str_contains($quelle, 'LIBXML_NOERR '), 'Der verkürzte Name steht noch im Code');
// LIBXML_NONET hält die Auflösung externer Entitäten vom Netz fern.
assertTrue(defined('LIBXML_NONET') && defined('LIBXML_NOERROR'));
});
};