コンテンツへスキップ

Phasis

JavaScriptエンジンをPHPで実装。ES2024+に対応し、test262の全50,506テストに合格(2025-05-05スナップショット)。URL、エンコーディング、structuredClone、fetch、Streamsも搭載。

ターミナル
composer require phasis/phasis

最新リリース v0.4.2 MIT PHP 8.2+, ext-bcmath, ext-curl, ext-mbstring

実践例

1つのエンジンオブジェクトで、PHPプロセス内のJavaScriptを実行し、双方向に値を受け渡せます。

PHPからJavaScriptを実行

Phasis\Engineは、呼び出し元のPHPプロセス内でソース文字列やファイルを評価します。setGlobal()はPHP配列をJavaScript配列やオブジェクトに変換し、PHPクロージャを関数としてラップします。

console.logの出力はエンジンにバッファされ、getConsoleOutput()で読み取ります。2つ目のタブにあるフォーマッターは、エンジンをまったく必要としません。

エンジン
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

ECMAScript適合性テストスイートの2025-05-05スナップショットに含まれる50,506件すべてに合格。すべてのカテゴリを実行し、スキップはありません。

最新のECMAScript

クラス、async/await、ジェネレーター、Symbol、BigInt、Proxy、Temporal、TypedArray、Intl(ext-intl使用)に対応。ES2024+の全機能を搭載。

Web Platform API

URL、TextEncoderとTextDecoder、atobとbtoa、structuredClone、performance、DOMExceptionを標準搭載。

fetch + ストリーム

ext-curl経由でJSから実際のHTTPにアクセスできます。AbortSignal、Blob、FormData、WHATWG Streamsを含むFetch APIに対応。

ウェブプラットフォームテスト

fetch、headers、blob、abort、streams、encodingのWPTサブテストを取り込み、brotliとSharedArrayBuffer関連の許可リスト対象を除いて合格します。

PHP ↔ JS連携

setGlobal()はPHPクロージャをJS関数として公開し、call()はPHPからJS関数を実行します。値は境界で変換され、配列はコピーされます。

組み込み可能

Engineクラス1つでeval、execFile、setGlobal、callを実行。あらゆるPHPアプリやCLIに組み込めます。

コールスタック上限

固定の4,096フレームのコールスタックにより、無限に続く再帰を捕捉可能なInternalErrorで停止します。

CLI

bin/phasisでファイルまたは-eスニペットを実行し、--astでASTを出力します。リポジトリのチェックアウトでは、bin/test262で適合性テストスイートを実行できます。

Node.jsオラクル

シナリオはNode.js(V8)と照合します。エンジンに関係する変更を含むpushでは、WPTとライブラリスイートをCIで実行します。test262全件の合格確認は任意に実行し、直近では2026-06-09に実施しました。

実際のライブラリ

acorn、mustache.js、lodash、markedなど204個のnpmパッケージをテストし、Nodeとバイト単位で同じ出力になることを確認しています。

Phasisを選ぶ理由

Node.jsプロセス不要

PhasisはPHP自体でJavaScriptを字句解析、構文解析、実行するため、Nodeのexec()呼び出しもFFIもありません。Composerパッケージとしてインストールできます。

ホストがfetchを制御

fetch()はデフォルトでext-curlを使用します。setFetchTransport()で転送方法を切り替えられます(テスト用のモックなど)。setFetchPolicy()を使えば、各リクエストの送信前に拒否または書き換えができます。

仮想時間でタイマーを実行

eval()は戻る前にイベントループを処理し、スリープする代わりに、次に保留中のタイマーまで時計を進めます。長時間稼働するホストでは、tickEventLoop()を使って実時間でループを動かせます。

パーサーとフォーマッターを内蔵

パーサーは型付きPHP ASTを返し、ESTree形式でエクスポートします。フォーマッターはJavaScript、JSON、CSSをprettier互換のレイアウトで再出力します。

との比較

PHPアプリケーションからJavaScriptを実行または処理するその他の方法。

他のツールとPhasisの比較
Node.js 得意なことNode.jsはV8エンジンでJavaScriptを実行し、node_modulesフォルダーからパッケージを解決するため、npm依存パッケージを名前で読み込めます。 Phasisとの違いPHPからNodeを呼び出すと、2つ目のランタイムとサブプロセスの境界が加わります。PhasisはPHP内で動作しますが、モジュールローダーにはnode_modulesもpackage.jsonエクスポートの解決機能もありません。そのため、esbuildなどでnpmパッケージを事前にバンドルする必要があります。
V8Js 得意なことV8JsはGoogleのV8エンジンをPHPに組み込み、JavaScriptを、時間とメモリの上限を設定できるサンドボックスで実行します。 Phasisとの違いV8Jsはlibv8ライブラリを必要とするコンパイル済み拡張機能です。PhasisはComposerから導入できる純粋なPHPで、ドキュメントによると、ディスパッチ処理が中心のコードではV8の実行時間の約100倍かかります。
Peast 得意なことPeastはPHP 5.4以降でJavaScriptをESTree ASTに解析し、ツリー走査、セレクタークエリ、レンダリング機能を追加します。 Phasisとの違いPhasisには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のドキュメントから、簡潔に回答します。

スタートガイドから始め、続けてAPIリファレンスでfetchフックとイベントループを確認してください。