Preskoči na vsebino

Znane omejitve

Phasis si prizadeva, da bi se pri vseh opazljivih testih specifikacije vedel enako kot V8. Ta stran opisuje primere, kjer se ta enakost v praksi konča — običajno zaradi temeljnih razlik med tolmačem PHP, ki obhaja drevo, in pogonom C++, prevedenim z JIT.

Omejitve zmogljivosti

Pogon uporablja obhod drevesa, priložnostni VM za bajtno kodo in transpajler JsToPhp, ki telesa z veliko števili ali lokalnimi spremenljivkami (vključno z oblikami obj.method(), new Ctor() in this.member) prevede v izvorna zaprtja PHP, ki jih lahko JIT sledenja v različici PHP 8.5 prevede v strojno kodo. Večina pogostih odpremljanj poteka znotraj zanke switch VM ali neposredno v kodi PHP, prevedeni z JIT — ne z obhodom AST — vendar vsaka operacija VM še vedno plača strošek odpremljanja PHP, vsaka oblika, ki je JsToPhp še ne podpira, pa preide na počasnejši VM. Zgornja meja za delovne obremenitve, omejene z odpremljanjem, je približno 100× počasnejša kot V8.

Pri vgradnih delovnih obremenitvah — izvajanju logike, ki jo posreduje uporabnik, nad podatki PHP, cevovodih za pretvorbo vsebine in pravilih za preverjanje veljavnosti — ta omejitev redko vpliva. V8 traja 100 ms; Phasis traja 10 s; oboje je precej pod časovno omejitvijo zahteve. Za dodatno zmanjšanje razlike bi bilo treba JsToPhp naučiti podpirati več oblik (sklepanje o vrstah parametrov, prevajanje await / yield*) ali neposredno ustvarjati ukaze opcache namesto prek eval(). Glejte Merila zmogljivosti § Načrt.

Sočasnost več agentov

Model JavaScript SharedArrayBuffer + Atomics.wait + postMessage predpostavlja, da lahko gostitelj izvaja prave niti operacijskega sistema. PHP tega ne zmore (brez pcntl_fork, ki ni na voljo v vseh gostiteljih).

Phasis simulira enega agenta — Atomics.wait takoj vrne »not-equal« ali »timed-out«, notify pa vedno vrne 0. S tem uspejo vsi testi test262, ki se izvajajo z enim agentom (preverjanje vhodnih podatkov, poti napak, prazno notify); to zajema 376 testov Atomics od skupno 376.

Testi, ki zahtevajo, da se dva sočasna agenta medsebojno opazujeta, niso podprti. Za pravo vzporednost uporabite čakalno vrsto za delovne procese na ravni PHP (Redis, Beanstalkd, …).

Semantika okolij

ShadowRealm je implementiran, vendar se vsako podrejeno okolje izvaja v istem procesu PHP kot gostitelj. Funkcije gostitelja lahko prenesejo sklice med okolji, če ne poskrbite, da je koda PHP ustrezno izolirana. Specifikacija to dovoljuje; V8 zagotavlja strožjo izolacijo z ločenimi primerki v8::Isolate.

createRealm() (kavelj gostitelja test262) interno ustvari novo okolje Phasis\Engine in vanj prenese standardno knjižnico.

Izbira pogona za regularne izraze

Phasis kot glavno zaledje za regularne izraze uporablja PCRE2, ki je del PHP, za primere, ki jih PCRE2 ne obravnava povsem natančno, pa uporablja lastni ujemalnik (pogled nazaj z zajemi, kvantificirane skupine s ponastavitvijo, določena semantika zastavice /v). Lastni ujemalnik je počasnejši od PCRE2 in se uporablja samo, kadar pošiljanje zazna nezdružljiv vzorec.

Pomembna posledica: tabela za pretvorbo velikosti črk v PCRE2 se lahko razlikuje od tabele v različici ICU, ki jo uporablja V8, zlasti v starejših distribucijah Linux (Ubuntu 22.04 vključuje ICU 70; Phasis priloži tabelo za pretvorbo velikosti črk ICU 76+ in tako prepreči odstopanja gostitelja pri vzorcih /iu).

Pomnilniški model

Zbiralnik smeti s štetjem sklicev v PHP se razlikuje od sledilnega zbiralnika v V8. Objekti PHP, ki jih zajamejo zaprtja gostitelja, ostanejo živi, dokler pogon ohranja ta zaprtja; cikli med njimi se ne zberejo, dokler ni uničen Engine. Za predpomnilnike, ki jih ne želite ohranjati v pomnilniku, uporabite WeakMap / WeakRef.

Introspekcijski API-ji process.memoryUsage() in podobni API-ji, specifični za V8, niso implementirani.

Nalagalnik modulov

Nalagalnik modulov ES razreši relativne uvoze glede na datotečni sistem, vendar ne podpira konvencij za povezovalnike paketov:

  • Brez razreševanja node_modules.
  • Brez preslikave package.json exports.
  • Brez sklepanja o končnici datoteke (zapisati morate import './foo.mjs', ne import './foo').
  • Brez uvozov HTTP.

To ustreza osnovni specifikaciji ECMAScript, ne pa vedenju Node. Kavelj za lastni razreševalnik modulov ne obstaja. Če želite uporabljati pakete npm, jih z orodjem, kot je esbuild, združite v en skript ali modul, preden ga posredujete Phasis.

Wasm

WebAssembly ni implementiran. Ni izvajalnika wasm PHP, na katerega bi ga bilo mogoče povezati.

Spletni API-ji, ki so na voljo samo v brskalniku

Phasis vključuje celoten Web Platform Pack (URL, TextEncoder/TextDecoder, atob/btoa, structuredClone, performance, DOMException), celoten Fetch Pack (fetch, Request, Response, Headers, Body, AbortController/AbortSignal, Blob/File, FormData, EventTarget/Event, celoten WHATWG Streams, navigator), poleg tega še crypto (getRandomValues, randomUUID, celoten SubtleCrypto: digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), WebSocket (konstruktor + kodirnik okvirjev RFC 6455, zamenljiv prenosni sloj), XMLHttpRequest (zgrajen na prenosnem sloju fetch) in pravo zanko dogodkov (setTimeout, setInterval, clearTimeout, clearInterval, queueMicrotask, AsyncContext). Glejte Spletni API-ji.

Česa ne vključuje:

  • window, document in drevesa DOM — Phasis ni brskalnik.
  • localStorage, sessionStorage, IndexedDB — zadevajo gostiteljsko okolje; vgrajevalnik skrbi za trajno shranjevanje.
  • Worker, SharedWorker, MessageChannel — zahtevajo prave niti operacijskega sistema, ki jih PHP ne ponuja.
  • Service Workers, Push API, Notifications, BroadcastChannel — zunaj brskalnika niso uporabni.

Globalni objekti Node

process, Buffer, __dirname, __filename, require() — nič od tega ni na voljo. Gre za konvencije gostiteljskega okolja Node, ne za jezikovne funkcije.

Če prenašate kodo Node, zamenjajte require('foo') z import 'foo', process.env.X nadomestite z env.X, vezanim na gostitelja, in v PHP posredujte poti, enakovredne __dirname.

Decimalna natančnost

Števila ECMAScript so 64-bitna števila z dvojno natančnostjo IEEE 754. Decimalna aritmetika z več kot 15 pomembnimi števkami izgubi natančnost, enako kot v vsakem drugem pogonu JS. Za natančno računanje s celimi števili uporabite BigInt, za natančno računanje z decimalnimi ulomki pa knjižnico za decimalna števila JS.

PHP interno uporablja bcmath za BigInt; edina prava razlika v primerjavi z V8 je počasnejše izvajanje zelo velikih operacij bigint v PHP kot v implementaciji C++ v V8. Številska pravilnost je enaka.