Phasis
En JavaScript-motor skrevet i PHP: ES2024+ består alle 50,506 test262-tests (øjebliksbillede fra 2025-05-05) samt URL, encoding, structuredClone, fetch og Streams.
composer require phasis/phasisSeneste udgivelse 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.jsI praksis
Ét engine-objekt kører JavaScript i PHP-processen og sender værdier begge veje.
Kør JavaScript fra PHP
Phasis\Engine evaluerer kildestrenge og filer i den PHP-proces, der kalder den. setGlobal() konverterer PHP-arrays til JavaScript-arrays og objekter og omslutter PHP-closures som funktioner.
console.log-output buffres i motoren og læses tilbage med getConsoleOutput(). Formateringen i den anden fane kræver slet ingen motor.
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"Ren PHP
Ingen exec(), ingen FFI, ingen Node. Kræver PHP 8.2+ med ext-curl, ext-bcmath og ext-mbstring; CI kører PHP 8.4 og 8.5.
100% test262
Består alle 50.506 tests i ECMAScripts overensstemmelsestestpakke i øjebliksbilledet fra 2025-05-05, alle kategorier, ingen oversprungne.
Moderne ECMAScript
Klasser, async/await, generators, Symbol, BigInt, Proxy, Temporal, TypedArray og Intl med ext-intl. Fuld ES2024+.
Webplatforms-API'er
URL, TextEncoder og TextDecoder, atob og btoa, structuredClone, performance og DOMException er indbygget.
fetch + Streams
Ægte HTTP fra JS via ext-curl. Fuld Fetch-API med AbortSignal, Blob, FormData og WHATWG Streams.
Web Platform Tests
Importerede WPT-deltests for fetch, headers, blob, abort, streams og encoding består, bortset fra en tilladelsesliste med brotli- og SharedArrayBuffer-tilfælde.
PHP ↔ JS-interoperabilitet
setGlobal() stiller PHP-closures til rådighed som JS-funktioner, og call() kører JS-funktioner fra PHP. Værdier konverteres ved grænsen; arrays kopieres.
Kan indlejres
Én Engine-klasse: eval, execFile, setGlobal, call. Kan indlejres i enhver PHP-app eller CLI.
Grænse for kaldestak
En fast kaldestak på 4.096 frames stopper løbsk rekursion med en fejl af typen InternalError, som kan opfanges.
CLI
bin/phasis kører en fil eller et -e-udsnit og udskriver AST'et med --ast. I en checkout af repositoriet kører bin/test262 overensstemmelsestestpakken.
Node.js-oracle
Scenarier kontrolleres mod Node.js (V8). WPT og bibliotekets testpakke køres i CI ved push, der berører motoren; den fulde test262-testkørsel startes efter behov, senest 2026-06-09.
Ægte biblioteker
204 npm-pakker, herunder acorn, mustache.js, lodash og marked, testes med output, der er byteidentisk med Node.
Hvorfor Phasis
Ingen Node.js-proces
Phasis leksikaliserer, parser og afvikler JavaScript i PHP selv, uden exec()-kald til Node og uden FFI. Den installeres som en Composer-pakke.
fetch styres af værtsprogrammet
fetch() bruger ext-curl som standard. setFetchTransport() udskifter transportlaget, for eksempel med en mock i tests, og setFetchPolicy() kan afvise eller omskrive hver anmodning, før den sendes.
Timere med virtuel tid
eval() tømmer hændelsesløkken, før den returnerer, og uret springer til den næste ventende timer i stedet for at vente. Værtsprogrammer med lang levetid kan drive løkken i realtid med tickEventLoop().
Parser og formattering inkluderet
Parseren returnerer et typet PHP-AST, der kan eksporteres til ESTree. Formatteringen udskriver JavaScript, JSON og CSS igen med et Prettier-kompatibelt layout.
Sammenlignet med
Andre måder at køre eller behandle JavaScript fra en PHP-applikation.
| Værktøj | God til | Forskel fra Phasis |
|---|---|---|
| Node.js | God tilNode.js kører JavaScript på V8-motoren og finder pakker i node_modules-mapper, så npm-afhængigheder indlæses ved navn. | Forskel fra PhasisAt kalde Node fra PHP tilføjer en ekstra runtime og en underprocesgrænse. Phasis kører i PHP, men dens modulindlæser har ingen node_modules- eller package.json-eksportopløsning, så npm-pakker først skal samles, for eksempel med esbuild. |
| V8Js | God tilV8Js indlejrer Googles V8-motor i PHP og kører JavaScript i en sandkasse, der kan begrænses med en tidsgrænse og en hukommelsesgrænse. | Forskel fra PhasisV8Js er en kompileret udvidelse, der kræver libv8-biblioteket. Phasis er ren PHP fra Composer, og dokumentationen angiver en køretid på cirka 100 gange V8s for kode, der er begrænset af dispatch. |
| Peast | God tilPeast parser JavaScript til et ESTree-AST på PHP 5.4 og nyere og tilføjer træ-gennemløb, selektorforespørgsler og rendering. | Forskel fra PhasisPhasis kræver PHP 8.2. Parseren returnerer typede, skrivebeskyttede nodeobjekter med en ESTree-eksport, og samme pakke kan også afvikle koden. |
| Prettier | God tilPrettier formaterer JavaScript, TypeScript, JSX, CSS, HTML, Markdown, YAML og mere og installeres fra npm. | Forskel fra PhasisFormatteringen i Phasis dækker kun JavaScript, JSON og CSS. Indstillingerne svarer til Prettier-3.x, og den kører i PHP uden Node.js. |
Spørgsmål og svar
Korte svar fra Phasis-dokumentationen.
Composer kræver PHP 8.2 eller nyere med bcmath, curl og mbstring. intl anbefales til Intl-API'er og Temporal-kalendere, der ikke bruger ISO, og openssl til AES-kryptering i crypto.subtle.
Phasis er en træ-gennemløbende fortolker med en bytekode-VM, ikke en JIT. Dokumentationen angiver en køretid på cirka 100 gange V8s for kode, der er begrænset af dispatch; ifølge dokumentationen betyder denne øvre grænse sjældent noget for indlejring, for eksempel af valideringsregler.
Ikke ved navn. Modulindlæseren finder importer i filsystemet, kræver eksplicitte filtypenavne og understøtter ikke node_modules eller package.json-eksporter, så saml en pakke med et værktøj som esbuild, og giv Phasis den samlede pakke.
Nej. window, document og DOM-træet følger ikke med, og det gør globale Node-objekter som process, Buffer og require() heller ikke.
Det buffres i motoren i stedet for at blive udskrevet. Læs det med getConsoleOutput() eller getConsoleLines(), og ryd bufferen med clearConsole().
Et uopfanget throw vises som Phasis\Exceptions\JsThrowable. Fejl, som motoren selv rejser, for eksempel ved læsning af en egenskab på null, vises som Phasis\Exceptions\TypeError, ReferenceError eller RangeError, og de nedarver alle fra Phasis\Exceptions\RuntimeError. Ugyldig kildekode kaster Phasis\Parser\ParseError, en Phasis\Exceptions\SyntaxError, med linje, kolonne og forskydning.
Begynd med introduktionsvejledningen, og læs derefter API-referencen om fetch-hooks og hændelsesløkken.