Ga naar de inhoud

Bekende beperkingen

Phasis streeft ernaar zich bij elke waarneembare specificatietest identiek te gedragen aan V8. Op deze pagina staan de situaties waarin die overeenkomst in de praktijk ophoudt — meestal door fundamentele verschillen tussen een tree-walking-PHP-interpreter en een JIT-gecompileerde C++-engine.

Prestatieplafond

De engine is een tree-walker met een bytecode-VM die waar mogelijk wordt gebruikt en een JsToPhp-transpiler die rekenintensieve en lokale variabelen bevattende code (waaronder patronen als obj.method(), new Ctor() en this.member) omzet in native PHP-closures, die de tracing-JIT van PHP 8.5 kan compileren naar machinecode. De meeste intensieve dispatch vindt plaats binnen de switch-loop van de VM of rechtstreeks in JIT-gecompileerde PHP — niet door de AST te doorlopen — maar elke VM-opcode kost nog steeds extra tijd voor dispatch via PHP, en codepatronen die JsToPhp nog niet ondersteunt, vallen terug op de tragere VM. Bij workloads die vooral door dispatch worden beperkt, ligt het plafond op ongeveer ~100× langzamer dan V8.

Voor workloads waarbij logica van gebruikers wordt uitgevoerd op PHP-gegevens, zoals inhoudstransformatiepijplijnen en validatieregels, is dit plafond zelden van belang. V8 duurt 100 ms; Phasis duurt 10 s; beide vallen ruim binnen de time-out voor verzoeken. Om het verschil verder te verkleinen, moet JsToPhp meer patronen leren verwerken (inferentie van parametertypen, omzetting van await / yield*) of rechtstreeks opcache-opcodes genereren in plaats van via eval(). Zie Benchmarks § Roadmap.

Gelijktijdigheid van meerdere agents

Het model van JavaScript met SharedArrayBuffer + Atomics.wait + postMessage gaat ervan uit dat de host echte OS-threads kan uitvoeren. PHP kan dat niet (zonder pcntl_fork, dat niet op elke host beschikbaar is).

Phasis simuleert één agent — Atomics.wait retourneert onmiddellijk "not-equal" of "timed-out" en notify retourneert altijd 0. Zo slagen alle test262-tests die met één agent worden uitgevoerd (invoervalidatie, foutpaden, lege notify-aanroep), wat 376 van de 376 Atomics-tests omvat.

Tests waarvoor twee gelijktijdige agents elkaar moeten waarnemen, worden niet ondersteund. Gebruik voor echte parallelle verwerking een workerrij op PHP-niveau (Redis, Beanstalkd, …).

Realm-semantiek

ShadowRealm is geïmplementeerd, maar elke child realm draait in hetzelfde PHP-proces als de host. Hostfuncties kunnen verwijzingen tussen realms laten lekken als je niet zorgvuldig voorkomt dat PHP-code er toegang toe krijgt. De specificatie staat dit toe; V8 dwingt strengere isolatie af met afzonderlijke v8::Isolate-instanties.

createRealm() (test262-hosthook) maakt intern een nieuwe Phasis\Engine aan en koppelt de standaardbibliotheek hieraan.

Keuze van regex-engine

Phasis gebruikt PCRE2 van PHP als primaire regex-backend, met een aangepaste matcher voor gevallen die PCRE2 niet exact aankan (lookbehind met captures, gekwantificeerde groepen met reset en bepaalde semantieken van /v-vlaggen). De aangepaste matcher is trager dan PCRE2 en wordt alleen gebruikt wanneer de dispatch een incompatibel patroon detecteert.

Het opvallende gevolg: PCRE2 kan een andere tabel voor hoofdletterconversie hebben dan de ICU-versie van V8, vooral op oudere distributies van Linux (Ubuntu 22.04 wordt geleverd met ICU 70; Phasis bevat een conversietabel van ICU 76+ om afwijkingen op de host bij /iu-patronen te ondervangen).

Geheugenmodel

De garbagecollector met referentietelling van PHP verschilt van de tracing garbagecollector van V8. PHP-objecten die door closures van de host worden vastgehouden, blijven bestaan zolang de engine die closures vasthoudt, en cycli ertussen worden pas opgeruimd wanneer Engine wordt vernietigd. Gebruik WeakMap / WeakRef voor caches die u niet in leven wilt houden.

process.memoryUsage() en vergelijkbare introspectie-API's die specifiek zijn voor V8 zijn niet geïmplementeerd.

Modulelader

De ES-modulelader lost relatieve imports op aan de hand van het bestandssysteem, maar begrijpt de conventies van bundlers niet:

  • Geen node_modules-resolutie.
  • Geen package.json-exports-map.
  • Geen afleiding van bestandsextensies (u moet import './foo.mjs' schrijven, niet import './foo').
  • Geen HTTP-imports.

Dit volgt de kale ECMAScript-specificatie, maar niet het gedrag van Node. Er is geen hook voor een aangepaste module-resolver. Om npm-pakketten te gebruiken, bundelt u ze met een tool zoals esbuild in één script of module voordat u die aan Phasis doorgeeft.

Wasm

WebAssembly is niet geïmplementeerd. Er is geen PHP-runtime voor wasm om aan te koppelen.

Overgeslagen browser-API's

Phasis bevat het volledige Web Platform Pack (URL, TextEncoder/TextDecoder, atob/btoa, structuredClone, performance, DOMException), het volledige Fetch Pack (fetch, Request, Response, Headers, Body, AbortController/AbortSignal, Blob/File, FormData, EventTarget/Event, volledige WHATWG Streams, navigator), plus crypto (getRandomValues, randomUUID, volledige SubtleCrypto: digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), WebSocket (constructor + RFC 6455-framecodec, verwisselbaar transport), XMLHttpRequest (gebouwd op het fetch-transport) en een echte eventloop (setTimeout, setInterval, clearTimeout, clearInterval, queueMicrotask, AsyncContext). Zie Web-API's.

Wat niet wordt meegeleverd:

  • window, document, de DOM-tree — Phasis is geen browser.
  • localStorage, sessionStorage, IndexedDB — zaken aan de hostzijde; de embedder beheert de persistentie.
  • Worker, SharedWorker, MessageChannel — hiervoor zijn echte OS-threads nodig, die PHP niet biedt.
  • Service Workers, Push API, meldingen, BroadcastChannel — niet relevant buiten een browser.

Globale variabelen van Node

process, Buffer, __dirname, __filename, require() — ook deze bestaan niet. Het zijn conventies van de Node-host, geen taalfuncties.

Als u Node-code overzet, vervangt u require('foo') door import 'foo', vervangt u process.env.X door een aan de host gebonden env.X en geeft u equivalente paden aan __dirname door vanuit PHP.

Decimale precisie

ECMAScript-getallen zijn IEEE 754-doubles. Decimale berekeningen met meer dan 15 significante cijfers verliezen precisie, net als in elke andere JS-engine. Gebruik BigInt voor exacte berekeningen met gehele getallen of een decimale bibliotheek van JS als u exacte berekeningen met breuken nodig hebt.

De bcmath van PHP wordt intern gebruikt voor BigInt; het enige echte verschil met V8 is dat zeer grote bigint-bewerkingen trager zijn in PHP dan in de C++-implementatie van V8. De numerieke correctheid is identiek.