Phasis
Енджин JavaScript, написан на PHP: ES2024+ преминава всички 50,506 тестове test262 (моментна снимка от 2025-05-05), както и URL, encoding, structuredClone, fetch и Streams.
composer require phasis/phasisПоследна версия 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.jsНа практика
Един обект на енджина изпълнява JavaScript в процеса PHP и предава стойности в двете посоки.
Изпълнявайте JavaScript от PHP
Phasis\Engine оценява низове с изходен код и файлове в процеса PHP, който го извиква. setGlobal() преобразува масивите PHP в масиви и обекти JavaScript, а затварянията на PHP обвива като функции.
Изходът на console.log се буферира в енджина и се прочита с getConsoleOutput(). Форматиращият инструмент във втория раздел не се нуждае от енджин.
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"Чисто PHP
Без exec(), FFI или Node. Изисква PHP 8.2+ с ext-curl, ext-bcmath и ext-mbstring; CI работи с PHP 8.4 и 8.5.
100% test262
Преминава всички 50 506 теста от набора за съответствие с ECMAScript към моментната снимка от 2025-05-05 — във всички категории, без пропуски.
Съвременен ECMAScript
Класове, async/await, генератори, Symbol, BigInt, Proxy, Temporal, TypedArray и Intl с ext-intl. Пълна поддръжка на ES2024+.
API на уеб платформата
URL, TextEncoder и TextDecoder, atob и btoa, structuredClone, performance и DOMException са вградени.
fetch + потоци
Реален HTTP от JS чрез ext-curl. Пълен Fetch API с AbortSignal, Blob, FormData и WHATWG Streams.
Тестове на уеб платформата
Импортираните WPT подтестове за fetch, headers, blob, abort, streams и encoding преминават, с изключение на включените в списъка случаи с brotli и SharedArrayBuffer.
Interop между PHP ↔ JS
setGlobal() предоставя PHP затваряния като функции на JS, а call() изпълнява функции на JS от PHP. Стойностите се преобразуват на границата, а масивите се копират.
Възможност за вграждане
Един клас Engine: eval, execFile, setGlobal, call. Вградете го във всяко приложение PHP или CLI.
Ограничение на стека за извиквания
Стек за извиквания с фиксиран капацитет от 4096 кадъра спира безкрайна рекурсия с уловима грешка InternalError.
CLI
bin/phasis изпълнява файл или фрагмент с -e и отпечатва AST с --ast. Във взето от хранилището копие bin/test262 изпълнява набора от тестове за съответствие.
Oracle за Node.js
Сценариите се проверяват спрямо Node.js (V8). WPT и библиотечният набор се изпълняват в CI при промени по енджина; пълният набор test262 се изпълнява при поискване, последно на 2026-06-09.
Реални библиотеки
Тестват се 204 пакета npm, включително acorn, mustache.js, lodash и marked, като изходът трябва да съвпада с този на Node до байт.
Защо Phasis
Без процес Node.js
Phasis лексикално анализира, парсва и изпълнява JavaScript в самия PHP, без извикване на Node чрез exec() и без FFI. Инсталира се като пакет Composer.
fetch под контрола на хоста
fetch() използва ext-curl по подразбиране. setFetchTransport() сменя транспорта, например с тестов mock, а setFetchPolicy() може да отказва или пренаписва всяка заявка преди изпращането ѝ.
Таймери във виртуално време
eval() изчерпва опашката на цикъла от събития, преди да се върне, а часовникът прескача към следващия чакащ таймер, вместо да изчаква. Хостове с продължително изпълнение могат да управляват цикъла в реално време с tickEventLoop().
Включени парсер и форматиращ инструмент
Парсерът връща типизирано AST PHP, което може да се експортира към ESTree. Форматиращият инструмент отпечатва отново JavaScript, JSON и CSS с оформление, съвместимо с prettier.
Сравнение с
Други начини за изпълнение или обработка на JavaScript от приложение PHP.
| Инструмент | Подходящ за | Разлики спрямо Phasis |
|---|---|---|
| Node.js | Подходящ заNode.js изпълнява JavaScript на енджина V8 и намира пакети в папки node_modules, така че зависимостите npm се зареждат по име. | Разлики спрямо PhasisИзвикването на Node от PHP добавя втори енджин и граница на подпроцес. Phasis работи в PHP, но модулният му зареждач няма node_modules или разрешаване на експорти package.json, затова пакетите npm трябва първо да се обединят, например с esbuild. |
| V8Js | Подходящ заV8Js вгражда енджина V8 на Google в PHP и изпълнява JavaScript в пясъчник, който може да се ограничи с лимит за време и памет. | Разлики спрямо PhasisV8Js е компилирано разширение, което изисква библиотеката libv8. Phasis е чист PHP от Composer, а документацията му посочва време за изпълнение около 100 пъти по-дълго от това на V8 при код, ограничен от разпределянето на изпълнението. |
| Peast | Подходящ заPeast парсва JavaScript в AST на ESTree с PHP 5.4 и по-нови версии, като добавя обхождане на дървото, заявки по селектори и рендиране. | Разлики спрямо PhasisPhasis изисква PHP 8.2. Парсерът му връща типизирани възли само за четене с експорт към ESTree, а същият пакет може и да изпълнява кода. |
| Prettier | Подходящ заPrettier форматира JavaScript, TypeScript, JSX, CSS, HTML, Markdown, YAML и други, и се инсталира от npm. | Разлики спрямо PhasisФорматиращият инструмент Phasis поддържа само JavaScript, JSON и CSS. Опциите му следват prettier 3.x и работи в PHP, без Node.js. |
Въпроси и отговори
Кратки отговори от документацията на Phasis.
Composer изисква PHP 8.2 или по-нова версия с bcmath, curl и mbstring. intl се препоръчва за API на Intl и календари Temporal, които не са ISO, а openssl — за AES криптиране в crypto.subtle.
Phasis е интерпретатор, който обхожда дърво, с виртуална машина за байткод, а не JIT. Документацията посочва време за изпълнение около 100 пъти по-дълго от това на V8 при код, ограничен от разпределянето на изпълнението — горна граница, която според нея рядко има значение при вграждане, например за правила за валидация.
Не по име. Модулният зареждач разрешава импорти спрямо файловата система, изисква изрични разширения на файловете и не поддържа node_modules или експорти package.json, затова обединете пакета с инструмент като esbuild и подайте на Phasis получения bundle.
Не. window, document и DOM дървото не са включени, нито пък глобални обекти на Node като process, Buffer и require().
Той се буферира в енджина, вместо да се отпечата. Прочетете го с getConsoleOutput() или getConsoleLines() и изпразнете буфера с clearConsole().
Неуловеното хвърляне на грешка се показва като Phasis\Exceptions\JsThrowable. Грешки, генерирани от самия енджин, например при четене на свойство на null, се показват като Phasis\Exceptions\TypeError, ReferenceError или RangeError, като всички те наследяват Phasis\Exceptions\RuntimeError. Невалиден изходен код хвърля Phasis\Parser\ParseError — Phasis\Exceptions\SyntaxError с номер на ред, колона и отместване.
Започнете с ръководството за първи стъпки, след което прочетете справочника API за кукичките на fetch и цикъла от събития.