Zum Inhalt springen

Performance

shikiphp führt echtes TextMate-Tokenizing in reinem PHP durch. Deshalb lohnt es sich, ehrlich zu sagen, was schnell ist und was nicht.

Was dich erwartet

Rechne pro Datei mit Dutzenden bis Hunderten Millisekunden, nicht mit Mikrosekunden. Der Tokenizer speichert kompilierte Regeln und Scanner zwischen. Grammatiken werden verzögert geladen (ein Beispiel, das keine eingebettete Sprache nutzt, muss sie nicht dekodieren). Die meisten Grammatikmuster laufen über natives preg_* in einem auf Äquivalenz geprüften PCRE-Schnellpfad; für den Rest kommt der Matcher in reinem PHP zum Einsatz (siehe Architektur).

Das sind Messwerte für wiederholte Einzelaufrufe aus dem Benchmark des Repositorys (bench/bench.php, Theme github-dark) auf einem Rechner, bei Korpusdateien mit etwa 55 bis 105 Zeilen:

Grammatik PHP 8.2 PHP 8.4
JSON, YAML 30–65 ms 25–45 ms
CSS, HTML 100–120 ms 80–100 ms
Python, Rust, Go, Bash, Markdown 190–220 ms 125–175 ms
PHP etwa 290 ms etwa 170 ms
TypeScript, TSX 490–510 ms 310–370 ms

Beim ersten Aufruf einer Sprache in einem Prozess fallen außerdem einmalig Kosten für das Laden und Kompilieren der Grammatik an: In denselben Läufen waren es 50–70 ms für JSON und etwas mehr als eine Sekunde für Markdown. Der Aufwand steigt mit der Komplexität der Grammatik und der Eingabegröße. Die Werte hängen von der Hardware ab, miss also auf deinem eigenen System: Klone das Repository und führe composer install und anschließend composer bench aus.

Sicherheitsvorkehrungen

Die Regex-Engine schützt vor ReDoS und merkt sich Fehlschläge, damit problematische Muster langsamer werden, statt zu hängen. Mit tokenizeMaxLineLength kannst du außerdem den Aufwand pro Zeile begrenzen. Bei Zeilen ab einer bestimmten Länge wird dann ein einzelnes Plain-Token ausgegeben — als Schutz vor gezielt präparierten einzeiligen Eingaben.

Caching in der Produktion

Am zuverlässigsten hältst du die Hervorhebung aus dem Request-Pfad heraus, indem du sie nicht bei jeder Anfrage ausführst. Derselbe Code mit denselben Optionen ergibt immer dasselbe HTML und lässt sich daher perfekt cachen:

  • Hebe Code für statische Websites und Dokumentation beim Build hervor.
  • Cache das gerenderte HTML (mit Code und Optionen als Schlüssel) für vom Nutzer bereitgestellte oder in einer Datenbank gespeicherte Snippets und verwende es erneut, bis sich der Quelltext ändert.

Verwende innerhalb eines Prozesses dieselbe Highlighter-Instanz wieder (die Shikiphp-Fassade übernimmt das für dich), damit Grammatik- und Theme-Caches über Aufrufe hinweg gemeinsam genutzt werden.