Ugrás a tartalomhoz

Ismert korlátok

Az Phasis célja, hogy minden megfigyelhető specifikációs tesztben azonosan viselkedjen az V8 motorral. Ez az oldal azokat a pontokat sorolja fel, ahol a gyakorlatban megszűnik ez az azonosság — jellemzően a faalapú PHP értelmező és a JIT-fordítású C++ motor alapvető különbségei miatt.

Teljesítménykorlát

A motor faalapú értelmezőt, alkalomszerűen használt bytecode VM-et és JsToPhp transzpílert alkalmaz, amely a számításigényes, illetve sok lokális változót használó függvénytörzseket (köztük a obj.method(), new Ctor() és this.member alakzatokat) natív PHP lezárásokká alakítja, amelyeket a PHP 8.5 nyomkövető JIT-je gépi kóddá fordíthat. A legtöbb forró diszpécselés a VM kapcsolóhurkán belül vagy közvetlenül a JIT által fordított PHP kódban zajlik — nem az AST bejárásával —, de minden VM-opkódra jut PHP diszpécselési költség, a JsToPhp által még nem kezelt alakzatok pedig visszaesnek a lassabb VM-re. A diszpécselés által korlátozott munkaterhelések felső határa nagyjából 100× lassabb, mint a V8.

Beágyazási munkaterheléseknél — például felhasználó által megadott logika futtatásakor PHP adatokon, tartalomátalakítási folyamatokban vagy érvényesítési szabályoknál — a korlát ritkán számít. A V8 ideje 100 ms; a Phasis ideje 10 s; mindkettő jóval a kérések időkorlátja alatt marad. A különbség további csökkentéséhez a JsToPhp-nak több alakzatot kellene kezelnie (paramétertípus-következtetés, await / yield* alakra hozás), vagy közvetlenül opcache-opkódokat kellene kibocsátania a eval() útján történő kibocsátás helyett. Lásd: Benchmarks § Roadmap.

Több ügynök egyidejű futtatása

Az JavaScript SharedArrayBuffer + Atomics.wait + postMessage modellje feltételezi, hogy a host valódi operációsrendszer-szálakat tud futtatni. Az PHP erre nem képes (pcntl_fork nélkül, amely nem minden hoston érhető el).

Az Phasis egyetlen ügynököt szimulál — az Atomics.wait azonnal „not-equal” vagy „timed-out” értéket ad vissza, az notify pedig mindig 0-t. Ez átmegy minden olyan test262 teszten, amely egyetlen ügynököt futtat (bemenet-ellenőrzés, hibautak, üres értesítés), ami az 376 Atomics-tesztek 376 részét fedi le.

A két egyidejű ügynök egymás megfigyelését igénylő teszteket a rendszer nem támogatja. Valódi párhuzamossághoz használjon munkafeldolgozó sort az PHP szintjén (Redis, Beanstalkd, …).

Realm-szemantika

ShadowRealm megvalósult, de minden gyermekrealm ugyanabban a PHP folyamatban fut, mint a gazdagép. A gazdagép függvényei hivatkozásokat szivárogtathatnak át a realmek között, hacsak nem ügyel arra, hogy a PHP kódot elszigetelje. A specifikáció ezt megengedi; a V8 szigorúbb elszigetelést biztosít különálló v8::Isolate-példányokkal.

A createRealm() (test262 gazdagépi hook) belsőleg létrehoz egy új Phasis\Engine-t, és áthidalja a standard könyvtárat.

A regexmotor kiválasztása

A Phasis elsődleges regex-háttérmotorként a PHP PCRE2-jét használja, olyan esetekre pedig, amelyeket a PCRE2 nem tud pontosan kezelni, egyéni illesztőt alkalmaz (capture-öket tartalmazó lookbehind, resetet tartalmazó kvantifikált csoportok, bizonyos /v-jelzőszemantikák). Az egyéni illesztő lassabb a PCRE2-nél, és csak akkor használja, ha az elosztó inkompatibilis mintát észlel.

Ennek fontos következménye, hogy a PCRE2 esetleg más kis- és nagybetű-összehasonlítási táblát használ, mint a V8 ICU-verziója, különösen régebbi Linux-disztribúciókon (az Ubuntu 22.04-es verziója ICU 70-et szállít; a Phasis egy ICU 76+-os kis- és nagybetű-összehasonlítási táblát csomagol, amely felülírja a gazdagépen tapasztalható eltéréseket a /iu mintáinál).

Memóriamodell

A PHP hivatkozásszámláló GC-je eltér a V8 nyomkövető szemétgyűjtőjétől. A gazdagép lezárásai által rögzített PHP-objektumok addig maradnak életben, amíg a motor megőrzi ezeket a lezárásokat; a köztük lévő ciklusok pedig nem gyűjtődnek be a Engine megsemmisítéséig. A nem életben tartandó gyorsítótárakhoz használja a WeakMap / WeakRef megoldást.

A process.memoryUsage() és a hasonló, V8-specifikus introspekciós API-k nincsenek megvalósítva.

Modultöltő

Az ES-modultöltő a fájlrendszerben oldja fel a relatív importokat, de nem ismeri a csomagolóeszközök konvencióit:

  • Nincs node_modules-feloldás.
  • Nincs package.json exports-térkép.
  • Nincs fájlkiterjesztés-következtetés (a import './foo.mjs' formát kell írni, nem a import './foo' formát).
  • Nincsenek HTTP-importok.

Ez megfelel a csupasz ECMAScript-specifikációnak, de nem a Node viselkedésének. Nincs hook egyéni modulfeloldóhoz. npm-csomagok használatához csomagolja őket egy eszközzel, például az esbuilddel, egyetlen szkriptbe vagy modulba, mielőtt átadja a Phasis-nek.

Wasm

A WebAssembly nincs megvalósítva. Nincs hozzá kapcsolható PHP wasm-futtatókörnyezet.

Kihagyott, csak böngészőben elérhető Web API-k

A Phasis a teljes Web Platform Pack csomagot szállítja (URL, TextEncoder/TextDecoder, atob/btoa, structuredClone, performance, DOMException), a teljes Fetch Pack csomagot (fetch, Request, Response, Headers, Body, AbortController/AbortSignal, Blob/File, FormData, EventTarget/Event, a teljes WHATWG Streams csomagot, navigator), továbbá a crypto csomagot (getRandomValues, randomUUID, teljes SubtleCrypto: digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), a WebSocket csomagot (konstruktor + RFC 6455-keretkódoló, cserélhető transzport), a XMLHttpRequest csomagot (a fetch-transzportra építve), valamint egy valódi eseményhurkot (setTimeout, setInterval, clearTimeout, clearInterval, queueMicrotask, AsyncContext). Lásd: Web API-k.

Amit nem szállít:

  • window, document és a DOM-fa — a Phasis nem böngésző.
  • localStorage, sessionStorage, IndexedDB — gazdagépoldali feladatok; az állandó tárolásról a beágyazó gondoskodik.
  • Worker, SharedWorker, MessageChannel — valódi operációsrendszer-szálakat igényelnek, amelyeket a PHP nem kínál.
  • Service Workers, Push API, értesítések, BroadcastChannel — böngészőn kívül irrelevánsak.

Node globális változói

A process, Buffer, __dirname, __filename, require() sem létezik. Ezek a Node gazdagépi konvenciói, nem a nyelv részei.

Ha Node-kódot portol, cserélje le a require('foo')-t erre: import 'foo'; a process.env.X helyett használjon gazdagéphez kötött env.X-t; és adja át a __dirname-nek megfelelő útvonalakat a PHP-ből.

Tizedes pontosság

Az ECMAScript-számok IEEE 754 típusú dupla pontosságú lebegőpontos számok. A 15-nél több értékes jegyet tartalmazó decimális műveletek ugyanúgy veszítenek a pontosságukból, mint bármely más JS-motorban. Pontos egész számokkal végzett matematikához használja a BigInt-t, pontos törtszámításokhoz pedig egy JS decimális könyvtárat.

A PHP bcmath-ja belsőleg a BigInt céljára szolgál; a V8-hez képest az egyetlen valódi különbség, hogy a nagyon nagy bigint-műveletek lassabbak a PHP-ban, mint a V8 C++-implementációjában. A numerikus helyesség azonos.