Перейти до вмісту

Phasis

Рушій JavaScript, написаний на PHP: ES2024+ із проходженням усіх 50 506 тестів test262 (знімок від 2025-05-05), а також URL, кодування, structuredClone, fetch і Streams.

Термінал
composer require phasis/phasis

Останній випуск v0.4.2 MIT PHP 8.2+, ext-bcmath, ext-curl, ext-mbstring

На практиці

Один об’єкт рушія запускає 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"

Повністю на 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.

Взаємодія PHP ↔ JS

setGlobal() надає замикання PHP як функції JS, а call() запускає функції JS з PHP. Значення конвертуються на межі; масиви копіюються.

Можна вбудовувати

Один клас Engine: eval, execFile, setGlobal, call. Додавайте його до будь-якого застосунку PHP або CLI.

Обмеження стека викликів

Фіксований стек викликів на 4 096 кадрів зупиняє неконтрольовану рекурсію помилкою InternalError, яку можна перехопити.

CLI

bin/phasis запускає файл або фрагмент -e і виводить AST за допомогою --ast. У клоні репозиторію bin/test262 запускає набір тестів на відповідність.

Оракул Node.js

Сценарії перевіряються за Node.js (V8). WPT і бібліотечний набір тестів запускаються в CI під час надсилання змін, що стосуються рушія; повний прогін test262 запускається на вимогу, востаннє — 2026-06-09.

Справжні бібліотеки

Перевіряються пакети npm 204, зокрема acorn, mustache.js, lodash і marked; їхній вивід побайтно збігається з Node.

Чому Phasis

Без процесу Node.js

Phasis виконує лексичний аналіз, розбирає та запускає JavaScript безпосередньо в PHP, без виклику Node через exec() і без FFI. Встановлюється як пакет Composer.

fetch під контролем хоста

fetch() за замовчуванням використовує ext-curl. setFetchTransport() дає змогу замінити транспорт, наприклад на макет для тестів, а 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 і новіших версіях та додає обхід дерева, запити селекторів і рендеринг. Відмінність від PhasisДля Phasis потрібна PHP 8.2. Його парсер повертає типізовані незмінні об’єкти вузлів з експортом ESTree; цей самий пакет також може виконувати код.
Prettier ПеревагиPrettier форматує JavaScript, TypeScript, JSX, CSS, HTML, Markdown, YAML та інші формати й встановлюється з npm. Відмінність від PhasisФорматувальник Phasis підтримує лише JavaScript, JSON і CSS. Його параметри відповідають 3.x prettier, а працює він у PHP без Node.js.

Запитання та відповіді

Короткі відповіді з документації Phasis.

Почніть із посібника з початку роботи, а потім прочитайте довідник API про хуки fetch і цикл подій.