Phasis
JavaScript engine napsaný v PHP: ES2024+ splňuje všechny testy test262 50,506 (snapshot z 2025-05-05) a nabízí také URL, kódování, structuredClone, fetch a Streams.
composer require phasis/phasisNejnovější vydání v0.4.2 MIT PHP 8.2+, ext-bcmath, ext-curl, ext-mbstring
./vendor/bin/phasis -e '1 + 2 * 3'
# 7
./vendor/bin/phasis -e '[1, 2, 3].map(x => x * x).join(",")'
# 1,4,9
./vendor/bin/phasis path/to/script.jsV praxi
Jeden objekt engine spouští JavaScript uvnitř procesu PHP a předává hodnoty oběma směry.
Spouštění JavaScript z PHP
Phasis\Engine vyhodnocuje zdrojové řetězce a soubory v procesu PHP, který jej volá. setGlobal() převádí pole PHP na pole a objekty JavaScript a uzávěry PHP obaluje jako funkce.
Výstup console.log se ukládá do vyrovnávací paměti enginu a čte se pomocí getConsoleOutput(). Formátovač na druhé kartě engine vůbec nepotřebuje.
use Phasis\Engine;
$engine = new Engine();
// Evaluate an expression
$engine->eval('1 + 2 * 3'); // 7
// Run a file
$engine->execFile('/path/to/script.js');
// Bridge a PHP value into JS (arrays are copied)
$engine->setGlobal('config', ['debug' => true]);
$engine->eval('config.debug'); // true
// console.log is buffered, not printed
$engine->eval('console.log("hi")');
echo $engine->getConsoleOutput(); // hi
// Expose a PHP closure as a JS function
$engine->setGlobal('greet', fn(string $name) => "Hello, $name");
$engine->eval('greet("world")'); // "Hello, world"use Phasis\Formatter\Formatter;
use Phasis\Formatter\FormatOptions;
$formatted = Formatter::formatSource(
"const a={x:1,y:2};",
'script',
new FormatOptions(useTabs: true, singleQuote: true),
);
// "const a = { x: 1, y: 2 };\n"Čisté PHP
Bez exec(), FFI i Node. Vyžaduje PHP 8.2+ s ext-curl, ext-bcmath a ext-mbstring; CI běží na PHP 8.4 a 8.5.
100% test262
Splňuje všechny testy 50 506 ze sady testů shody s ECMAScriptem ve snapshotu z 2025-05-05, ve všech kategoriích a bez vynechaných testů.
Moderní ECMAScript
Třídy, async/await, generátory, Symbol, BigInt, Proxy, Temporal, TypedArray a Intl s ext-intl. Plná podpora ES2024+.
Rozhraní webové platformy
Vestavěné jsou URL, TextEncoder a TextDecoder, atob a btoa, structuredClone, performance a DOMException.
fetch + Streams
Skutečné HTTP z JS přes ext-curl. Plné Fetch API s AbortSignal, Blob, FormData a WHATWG Streams.
Testy webové platformy
Importované podtesty WPT pro fetch, headers, blob, abort, streams a encoding procházejí, s výjimkou případů brotli a SharedArrayBuffer uvedených na seznamu povolených.
PHP ↔ interoperabilita JS
setGlobal() zpřístupňuje uzávěry PHP jako funkce JS a call() spouští funkce JS z PHP. Hodnoty se převádějí na hranici; pole se kopírují.
Lze vložit
Jedna třída Engine: eval, execFile, setGlobal, call. Lze vložit do libovolné aplikace PHP nebo CLI.
Limit hloubky volání
Pevně daný zásobník volání s limitem 4 096 rámců zastaví nekonečnou rekurzi a vyvolá zachytitelnou chybu InternalError.
CLI
bin/phasis spustí soubor nebo úryvek předaný pomocí -e a vypíše AST s --ast. V klonu repozitáře spustí bin/test262 sadu testů shody.
Oracle Node.js
Scénáře se ověřují proti Node.js (V8). WPT a sada testů knihovny se v CI spouštějí při pushích, které mění engine; kompletní testy test262 se spouštějí na vyžádání, naposledy 2026-06-09.
Skutečné knihovny
Testují se balíčky 204 npm, například acorn, mustache.js, lodash a marked; jejich výstup je bajt po bajtu shodný s Node.
Proč Phasis
Bez procesu Node.js
Phasis lexuje, parsuje a spouští JavaScript přímo v PHP, bez volání exec() do Node a bez FFI. Instaluje se jako balíček Composer.
fetch pod kontrolou hostitele
fetch() ve výchozím nastavení používá ext-curl. setFetchTransport() mění přenosovou vrstvu, například za mock v testech, a setFetchPolicy() může každý požadavek před odesláním zamítnout nebo upravit.
Časovače ve virtuálním čase
eval() před návratem vyprázdní smyčku událostí a hodiny přeskočí k dalšímu čekajícímu časovači místo čekání. Dlouhodobě běžící hostitelé mohou smyčku řídit v reálném čase pomocí tickEventLoop().
Parser a formátovač v ceně
Parser vrací typovaný AST PHP, který lze exportovat do ESTree. Formátovač znovu vypisuje JavaScript, JSON a CSS v rozložení kompatibilním s prettier.
Srovnání
Další způsoby spouštění nebo zpracování JavaScript z aplikace PHP.
| Nástroj | Vhodné pro | Rozdíl oproti Phasis |
|---|---|---|
| Node.js | Vhodné proNode.js spouští JavaScript v enginu V8 a vyhledává balíčky ve složkách node_modules, takže závislosti npm lze načítat podle názvu. | Rozdíl oproti PhasisVolání Node z PHP přidává druhé běhové prostředí a hranici podprocesu. Phasis běží uvnitř PHP, ale jeho načítání modulů nepodporuje node_modules ani rozlišení exportů package.json, takže se balíčky npm nejprve sbalí, například pomocí esbuild. |
| V8Js | Vhodné proV8Js vkládá engine V8 od Google do PHP a spouští JavaScript v izolovaném prostředí, jehož běh lze omezit časovým limitem a limitem paměti. | Rozdíl oproti PhasisV8Js je kompilované rozšíření, které vyžaduje knihovnu libv8. Phasis je čisté PHP od Composer; jeho dokumentace uvádí, že běží přibližně 100krát rychleji než V8 u kódu omezeného voláním funkcí. |
| Peast | Vhodné proPeast parsuje JavaScript do AST ESTree v PHP 5.4 a novějších verzích a přidává procházení stromu, dotazy pomocí selektorů a vykreslování. | Rozdíl oproti PhasisPhasis vyžaduje PHP 8.2. Jeho parser vrací typované objekty uzlů jen pro čtení s exportem ESTree a stejný balíček umí také spouštět kód. |
| Prettier | Vhodné proPrettier formátuje JavaScript, TypeScript, JSX, CSS, HTML, Markdown, YAML a další jazyky a instaluje se z npm. | Rozdíl oproti PhasisFormátovač Phasis podporuje pouze JavaScript, JSON a CSS. Jeho možnosti odpovídají 3.x prettier a běží v PHP, bez Node.js. |
Otázky a odpovědi
Stručné odpovědi z dokumentace Phasis.
Composer vyžaduje PHP 8.2 nebo novější s bcmath, curl a mbstring. Pro rozhraní Intl a kalendáře Temporal mimo ISO se doporučuje intl; pro šifrování AES v crypto.subtle pak openssl.
Phasis je interpret procházející strom s virtuálním strojem pro bajtkód, nikoli JIT. Dokumentace uvádí, že u kódu omezeného voláním funkcí běží přibližně 100krát rychleji než V8; tohoto limitu se při vkládání, například pro validační pravidla, podle ní dosahuje jen zřídka.
Ne podle názvu. Načítání modulů řeší importy vůči souborovému systému, vyžaduje výslovné přípony souborů a nepodporuje node_modules ani exporty package.json, proto balíček sbalte pomocí nástroje, jako je esbuild, a předejte Phasis vytvořený balíček.
Ne. window, document ani strom DOM nejsou součástí a chybí také globální proměnné Node, jako jsou process, Buffer a require().
Ukládá se do vyrovnávací paměti enginu, místo aby se vypisoval. Přečtěte jej pomocí getConsoleOutput() nebo getConsoleLines() a vyprázdněte vyrovnávací paměť pomocí clearConsole().
Nezachycená výjimka se projeví jako Phasis\Exceptions\JsThrowable. Chyby, které engine vyvolá sám, například při čtení vlastnosti hodnoty null, se projeví jako Phasis\Exceptions\TypeError, ReferenceError nebo RangeError a všechny dědí z Phasis\Exceptions\RuntimeError. Neplatný zdrojový kód vyvolá Phasis\Parser\ParseError, což je Phasis\Exceptions\SyntaxError s uvedením řádku, sloupce a posunu.
Začněte průvodcem pro začátek a potom si přečtěte referenční příručku API, kde najdete háčky fetch a smyčku událostí.