Vai al contenuto

Phasis

Un motore JavaScript scritto in PHP: ES2024+, tutti i 50.506 test test262 superati (snapshot del 2025-05-05), più URL, codifica, structuredClone, fetch e Streams.

Terminale
composer require phasis/phasis

Ultima versione v0.4.2 MIT PHP 8.2+, ext-bcmath, ext-curl, ext-mbstring

Nella pratica

Un singolo oggetto engine esegue JavaScript all’interno del processo PHP e consente di passare valori in entrambe le direzioni.

Eseguire JavaScript da PHP

Phasis\Engine valuta stringhe sorgente e file nel processo PHP che lo invoca. setGlobal() converte gli array PHP in array e oggetti JavaScript e avvolge le closure PHP come funzioni.

L’output di console.log viene memorizzato nel motore e letto con getConsoleOutput(). Il formatter nella seconda scheda non richiede alcun motore.

Motore
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 puro

Nessun exec(), nessun FFI, nessun Node. Richiede PHP 8.2+ con ext-curl, ext-bcmath ed ext-mbstring; la CI usa PHP 8.4 e 8.5.

100% test262

Supera tutti i 50.506 test della suite di conformità ECMAScript nello snapshot del 2025-05-05, in ogni categoria e senza esclusioni.

ECMAScript moderno

Classi, async/await, generatori, Symbol, BigInt, Proxy, Temporal, TypedArray e Intl con ext-intl. ES2024+ completo.

API della piattaforma web

URL, TextEncoder e TextDecoder, atob e btoa, structuredClone, performance e DOMException sono integrati.

fetch + Streams

HTTP reali da JS tramite ext-curl. Fetch API completo con AbortSignal, Blob, FormData e WHATWG Streams.

Test della piattaforma web

I sottotest WPT importati per fetch, headers, blob, abort, streams ed encoding vengono superati, tranne i casi brotli e SharedArrayBuffer inclusi in una allowlist.

Interop PHP ↔ JS

setGlobal() espone le closure PHP come funzioni JS e call() esegue le funzioni JS da PHP. I valori vengono convertiti al confine; gli array vengono copiati.

Integrabile

Una sola classe Engine: eval, execFile, setGlobal, call. Integratela in qualsiasi app PHP o CLI.

Limite dello stack di chiamate

Uno stack di chiamate fisso da 4.096 frame blocca la ricorsione incontrollata con un InternalError intercettabile.

CLI

bin/phasis esegue un file o uno snippet -e e stampa l’AST con --ast. In un checkout del repository, bin/test262 esegue la suite di conformità.

Oracle Node.js

Gli scenari vengono verificati con Node.js (V8). WPT e la suite della libreria vengono eseguiti in CI nei push che modificano il motore; il test completo test262 viene eseguito su richiesta, l’ultima volta il 2026-06-09.

Librerie reali

Vengono testati 204 pacchetti npm, tra cui acorn, mustache.js, lodash e marked, con output identico byte per byte a Node.

Perché Phasis

Nessun processo Node.js

Phasis analizza ed esegue JavaScript direttamente in PHP, senza chiamate exec() a Node e senza FFI. Si installa come pacchetto Composer.

fetch sotto il controllo dell’host

fetch() usa ext-curl per impostazione predefinita. setFetchTransport() sostituisce il trasporto, ad esempio con un mock nei test, mentre setFetchPolicy() può bloccare o riscrivere ogni richiesta prima dell’invio.

Timer basati sul tempo virtuale

eval() svuota il ciclo degli eventi prima di restituire il controllo e fa avanzare l’orologio al timer in attesa successivo invece di attendere. Gli host di lunga durata possono eseguire il ciclo in tempo reale con tickEventLoop().

Parser e formatter inclusi

Il parser restituisce un AST tipizzato PHP che esporta in ESTree. Il formatter ristampa JavaScript, JSON e CSS con un layout compatibile con prettier.

A confronto con

Altri modi per eseguire o elaborare JavaScript da un’applicazione PHP.

Phasis a confronto con altri strumenti
Node.js Ideale perNode.js esegue JavaScript con il motore V8 e risolve i pacchetti dalle cartelle node_modules, così le dipendenze npm vengono caricate per nome. Differenze rispetto a PhasisChiamare Node da PHP aggiunge un secondo runtime e il confine di un sottoprocesso. Phasis viene eseguito all’interno di PHP, ma il suo loader di moduli non supporta node_modules né la risoluzione delle esportazioni package.json, quindi i pacchetti npm vanno prima inclusi in un bundle, ad esempio con esbuild.
V8Js Ideale perV8Js integra il motore V8 di Google in PHP ed esegue JavaScript in una sandbox con limiti configurabili di tempo e memoria. Differenze rispetto a PhasisV8Js è un’estensione compilata che richiede la libreria libv8. Phasis è scritto interamente in PHP da Composer e, secondo la documentazione, ha un runtime circa 100 volte quello di V8 con codice limitato dalla distribuzione delle chiamate.
Peast Ideale perPeast analizza JavaScript in un AST ESTree su PHP 5.4 e versioni successive, aggiungendo attraversamento dell’albero, query con selettori e rendering. Differenze rispetto a PhasisPhasis richiede PHP 8.2. Il suo parser restituisce oggetti nodo tipizzati e di sola lettura, con esportazione ESTree; lo stesso pacchetto può anche eseguire il codice.
Prettier Ideale perPrettier formatta JavaScript, TypeScript, JSX, CSS, HTML, Markdown, YAML e altri formati, e si installa da npm. Differenze rispetto a PhasisIl formatter Phasis supporta solo JavaScript, JSON e CSS. Le sue opzioni rispecchiano quelle di prettier 3.x ed è eseguito in PHP, senza Node.js.

Domande e risposte

Risposte brevi dalla documentazione di Phasis.

Iniziate con la guida introduttiva, poi consultate il riferimento API per gli hook di fetch e il ciclo degli eventi.