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
./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.jsΣτην πράξη
Ένα αντικείμενο μηχανής εκτελεί 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"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
Χωρίς 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 εκτελεί τη σουίτα συμμόρφωσης.
Oracle Node.js
Τα σενάρια ελέγχονται σε σύγκριση με το Node.js (V8). Τα WPT και η σουίτα βιβλιοθήκης εκτελούνται στο CI σε ενημερώσεις που αγγίζουν τη μηχανή· η πλήρης εκτέλεση test262 γίνεται κατ' απαίτηση, τελευταία φορά στις 2026-06-09.
Πραγματικές βιβλιοθήκες
Δοκιμάζονται 204 πακέτα npm, μεταξύ αυτών τα acorn, mustache.js, lodash και marked, με έξοδο πανομοιότυπη σε επίπεδο byte με εκείνη του Node.
Γιατί Phasis
Χωρίς διεργασία Node.js
Το Phasis αναλύει και εκτελεί το JavaScript μέσα στο ίδιο το PHP, χωρίς κλήση exec() προς το Node και χωρίς FFI. Εγκαθίσταται ως πακέτο Composer.
fetch υπό τον έλεγχο του περιβάλλοντος φιλοξενίας
Το fetch() χρησιμοποιεί το ext-curl από προεπιλογή. Το setFetchTransport() αλλάζει τη μεταφορά, για παράδειγμα σε ένα mock για δοκιμές, και το 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 σε περιβάλλον απομόνωσης με δυνατότητα περιορισμού μέσω χρονικού ορίου και ορίου μνήμης. | Διαφορά με το PhasisΤο V8Js είναι μεταγλωττισμένη επέκταση που απαιτεί τη βιβλιοθήκη 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.
Το Composer απαιτεί PHP 8.2 ή νεότερη έκδοση με bcmath, curl και mbstring. Συνιστάται το intl για τα API Intl και τα ημερολόγια Temporal εκτός ISO, καθώς και το openssl για κρυπτογράφηση AES στο crypto.subtle.
Το Phasis είναι διερμηνευτής που διασχίζει δέντρα, με εικονική μηχανή bytecode, όχι JIT. Η τεκμηρίωση το εκτιμά σε περίπου 100 φορές τον χρόνο εκτέλεσης του V8 σε κώδικα που περιορίζεται από την αποστολή κλήσεων· ένα ανώτατο όριο που, όπως αναφέρει, σπάνια έχει σημασία για εργασίες ενσωμάτωσης, όπως οι κανόνες επικύρωσης.
Όχι με βάση το όνομα. Ο φορτωτής μονάδων επιλύει τις εισαγωγές με βάση το σύστημα αρχείων, απαιτεί ρητές επεκτάσεις αρχείων και δεν υποστηρίζει node_modules ή εξαγωγές package.json, επομένως συναρμολογήστε ένα πακέτο με ένα εργαλείο όπως το esbuild και περάστε το πακέτο στο Phasis.
Όχι. Τα window, document και το δέντρο DOM δεν περιλαμβάνονται, ούτε και καθολικά αντικείμενα του Node, όπως τα process, Buffer και require().
Αποθηκεύεται προσωρινά στη μηχανή αντί να εκτυπώνεται. Διαβάστε την με το getConsoleOutput() ή το getConsoleLines() και αδειάστε την προσωρινή μνήμη με το clearConsole().
Μια εξαίρεση που δεν έχει συλληφθεί εμφανίζεται ως Phasis\Exceptions\JsThrowable. Τα σφάλματα που προκαλεί ο ίδιος ο κινητήρας, όπως η ανάγνωση μιας ιδιότητας του null, εμφανίζονται ως Phasis\Exceptions\TypeError, ReferenceError ή RangeError και όλα επεκτείνουν το Phasis\Exceptions\RuntimeError. Ο μη έγκυρος πηγαίος κώδικας προκαλεί Phasis\Parser\ParseError, ένα Phasis\Exceptions\SyntaxError, με τη γραμμή, τη στήλη και τη θέση.
Ξεκινήστε με τον οδηγό γρήγορης εκκίνησης και, στη συνέχεια, διαβάστε την αναφορά API για τα fetch hooks και τον βρόχο συμβάντων.