Performance
shikiphp does real TextMate tokenization in pure PHP, so it is worth being honest about where it is fast and where it is not.
What to expect
Expect tens to hundreds of milliseconds per file, not microseconds. The
tokenizer caches compiled rules and scanners, grammars load lazily (a sample
that never touches an embedded language never pays to decode it), and most
grammar patterns run through native preg_* on an equivalence-gated PCRE fast
path, with the pure-PHP matcher handling the rest (see
Architecture).
These are warm, single-call times from the repository's benchmark
(bench/bench.php, theme github-dark) on one machine, for corpus files of
roughly 55 to 105 lines:
| Grammar | 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 | about 290 ms | about 170 ms |
| TypeScript, TSX | 490–510 ms | 310–370 ms |
The first call for a language in a process also pays one-time grammar loading
and compilation: in the same runs that ranged from 50–70 ms for JSON to just
over a second for Markdown. Cost scales with grammar complexity and input size,
and the figures move with hardware, so measure on your own: in a clone of the
repository, run composer install and then composer bench.
Safety guards
The regex engine includes failure-memoization and ReDoS protection so a
pathological pattern degrades rather than hanging. You can also cap per-line work
with tokenizeMaxLineLength, which emits a
single plain token for any line at or beyond a given length — a guard against
adversarial single-line inputs.
Cache in production
The reliable way to keep highlighting off your request path is to not run it on every request. Highlighting the same code with the same options always produces the same HTML, so it caches perfectly:
- Highlight at build time for static sites and documentation.
- Cache the rendered HTML (keyed by code + options) for user-supplied or database-stored snippets, and reuse it until the source changes.
Within a process, reuse a single highlighter (the Shikiphp facade does this for
you) so grammar and theme caches are shared across calls.