Phasis
Um mecanismo JavaScript escrito em PHP: passa em todos os testes 50 506 test262 ES2024+ (instantâneo de 2025-05-05), além de URL, codificação, structuredClone, fetch e Streams.
composer require phasis/phasisVersão mais recente 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.jsNa prática
Um único objeto de mecanismo executa JavaScript dentro do processo PHP e transfere valores nas duas direções.
Execute JavaScript a partir de PHP
Phasis\Engine avalia strings de código-fonte e arquivos no processo PHP que o chama. setGlobal() converte arrays de PHP em arrays e objetos de JavaScript, e encapsula closures de PHP como funções.
A saída de console.log fica em buffer no mecanismo e pode ser lida com getConsoleOutput(). O formatador na segunda aba não precisa de mecanismo.
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 puro
Sem exec(), sem FFI, sem Node. Requer PHP 8.2+ com ext-curl, ext-bcmath e ext-mbstring; a CI executa PHP 8.4 e 8.5.
100% test262
Passa nos 50 506 testes do conjunto de conformidade ECMAScript no instantâneo de 2025-05-05, em todas as categorias, sem ignorar nenhum teste.
ECMAScript moderno
Classes, async/await, geradores, Symbol, BigInt, Proxy, Temporal, TypedArray e Intl com ext-intl. ES2024+ completo.
APIs da plataforma Web
URL, TextEncoder e TextDecoder, atob e btoa, structuredClone, performance e DOMException já vêm integrados.
fetch + Streams
HTTP reais de JS via ext-curl. Fetch API completo com AbortSignal, Blob, FormData e WHATWG Streams.
Testes da plataforma Web
Os subtestes WPT importados para fetch, headers, blob, abort, streams e encoding passam, exceto pelos casos de brotli e SharedArrayBuffer em uma lista de permissões.
Interop de PHP ↔ JS
setGlobal() expõe closures PHP como funções JS, e call() executa funções JS a partir de PHP. Os valores são convertidos na fronteira; os arrays são copiados.
Incorporável
Uma classe Engine: eval, execFile, setGlobal, call. Integre-a a qualquer aplicação PHP ou CLI.
Limite da pilha de chamadas
Uma pilha de chamadas fixa de 4 096 quadros interrompe a recursão descontrolada com um InternalError capturável.
CLI
bin/phasis executa um arquivo ou trecho -e e imprime a AST com --ast. Em um clone do repositório, bin/test262 executa o conjunto de testes de conformidade.
Oráculo Node.js
Os cenários são verificados com Node.js (V8). WPT e o conjunto de testes da biblioteca são executados na CI em envios que alteram o mecanismo; a execução completa de test262 ocorre sob demanda, mais recentemente em 2026-06-09.
Bibliotecas reais
204 pacotes npm, entre eles acorn, mustache.js, lodash e marked, são testados com saída idêntica byte a byte à do Node.
Por que Phasis
Sem processo Node.js
Phasis analisa léxica e sintaticamente e executa JavaScript no próprio PHP, sem chamada exec() ao Node e sem FFI. É instalado como um pacote Composer.
fetch sob controle do host
fetch() usa ext-curl por padrão. setFetchTransport() substitui o transporte, por exemplo por um mock nos testes, e setFetchPolicy() pode bloquear ou reescrever cada solicitação antes do envio.
Temporizadores com tempo virtual
eval() esvazia o loop de eventos antes de retornar, e o relógio avança até o próximo temporizador pendente em vez de esperar. Hosts de longa duração podem executar o loop em tempo real com tickEventLoop().
Parser e formatador incluídos
O parser retorna uma AST tipada PHP que pode ser exportada para ESTree. O formatador imprime novamente JavaScript, JSON e CSS com um layout compatível com prettier.
Comparação com
Outras maneiras de executar ou processar JavaScript em uma aplicação PHP.
| Ferramenta | Ideal para | Diferenças em relação a Phasis |
|---|---|---|
| Node.js | Ideal paraNode.js executa JavaScript no mecanismo V8 e resolve pacotes em pastas node_modules, então dependências npm são carregadas pelo nome. | Diferenças em relação a PhasisChamar Node a partir de PHP adiciona um segundo ambiente de execução e uma fronteira de subprocesso. Phasis executa dentro de PHP, mas seu carregador de módulos não tem node_modules nem resolução de exports package.json; por isso, pacotes npm precisam ser empacotados antes, por exemplo com esbuild. |
| V8Js | Ideal paraV8Js incorpora o mecanismo V8 de Google em PHP e executa JavaScript em uma sandbox que pode ser restringida por limites de tempo e memória. | Diferenças em relação a PhasisV8Js é uma extensão compilada que precisa da biblioteca libv8. Phasis é PHP puro de Composer, e sua documentação estima um tempo de execução cerca de 100 vezes maior que o de V8 em código limitado pela distribuição de chamadas. |
| Peast | Ideal paraPeast analisa JavaScript em uma AST ESTree no PHP 5.4 e versões posteriores, adicionando percurso da árvore, consultas por seletores e renderização. | Diferenças em relação a PhasisPhasis requer PHP 8.2. Seu parser retorna objetos de nós tipados e somente para leitura, com exportação ESTree, e o mesmo pacote também pode executar o código. |
| Prettier | Ideal paraPrettier formata JavaScript, TypeScript, JSX, CSS, HTML, Markdown, YAML e mais, e pode ser instalado de npm. | Diferenças em relação a PhasisO formatador Phasis cobre apenas JavaScript, JSON e CSS. Suas opções seguem as de prettier 3.x e ele é executado em PHP, sem Node.js. |
Perguntas e respostas
Respostas curtas da documentação do Phasis.
Composer requer PHP 8.2 ou posterior com bcmath, curl e mbstring. intl é recomendado para as APIs Intl e calendários Temporal não-ISO, e openssl para criptografia AES em crypto.subtle.
Phasis é um interpretador que percorre árvores com uma VM de bytecode, não um JIT. A documentação estima um tempo de execução cerca de 100 vezes maior que o de V8 em código limitado pela distribuição de chamadas; segundo ela, esse limite raramente importa em tarefas de incorporação, como regras de validação.
Não pelo nome. O carregador de módulos resolve importações no sistema de arquivos, exige extensões de arquivo explícitas e não oferece suporte a node_modules nem a exports package.json; portanto, empacote o pacote com uma ferramenta como esbuild e passe o bundle a Phasis.
Não. window, document e a árvore DOM não são incluídos, assim como as variáveis globais do Node, como process, Buffer e require().
Ela fica em buffer no mecanismo, em vez de ser impressa. Leia-a com getConsoleOutput() ou getConsoleLines() e esvazie o buffer com clearConsole().
Uma exceção não capturada é apresentada como Phasis\Exceptions\JsThrowable. Erros gerados pelo próprio mecanismo, como ler uma propriedade de null, são apresentados como Phasis\Exceptions\TypeError, ReferenceError ou RangeError, e todos estendem Phasis\Exceptions\RuntimeError. Código-fonte inválido gera Phasis\Parser\ParseError, um Phasis\Exceptions\SyntaxError, com linha, coluna e deslocamento.
Comece pelo guia de introdução e depois consulte a referência API para os hooks de fetch e o loop de eventos.