
# Bekannte Einschränkungen

Phasis soll sich bei allen beobachtbaren Spezifikationstests wie V8 verhalten. Diese Seite beschreibt, wo diese Übereinstimmung in der Praxis endet — meist aufgrund grundlegender Unterschiede zwischen einem Tree-Walking-PHP-Interpreter und einer JIT-kompilierten C++-Engine.

## Leistungsgrenze

Die Engine ist ein Tree-Walker mit einer opportunistischen Bytecode-VM und einem JsToPhp-Transpiler, der numerische und lokale Variablen stark nutzende Funktionskörper (einschließlich der Formen `obj.method()`, `new Ctor()` und `this.member`) in native PHP-Closures umwandelt, die der Tracing-JIT von PHP 8.5 zu Maschinencode kompilieren kann. Der Großteil der häufigen Dispatches findet in der Switch-Schleife der VM oder direkt in JIT-kompiliertem PHP statt – nicht durch das Durchlaufen des AST. Jeder VM-Opcode verursacht jedoch weiterhin Dispatch-Overhead von PHP, und Formen, die JsToPhp noch nicht unterstützt, fallen auf die langsamere VM zurück. Bei workloads, die durch Dispatch begrenzt sind, liegt die Obergrenze bei ungefähr **~100× langsamer als V8**.

Bei eingebetteten Anwendungen – etwa beim Ausführen von nutzerdefinierter Logik auf PHP-Daten, in Inhaltsverarbeitungspipelines oder Validierungsregeln – ist diese Obergrenze selten entscheidend. V8 benötigt 100 ms, Phasis 10 s; beides liegt deutlich unter dem Zeitlimit für Anfragen. Um den Abstand weiter zu verkleinern, müsste JsToPhp mehr Formen unterstützen (Inferenz von Parametertypen, Absenkung von `await` / `yield*`) oder direkt Opcache-Opcodes statt über `eval()` ausgeben. Siehe [Benchmarks § Roadmap](https://phasis.inline0.dev/de/docs/advanced/benchmarks#roadmap).

## Nebenläufigkeit mehrerer Agenten

Das Modell von JavaScript mit `SharedArrayBuffer` + `Atomics.wait` + `postMessage` setzt voraus, dass der Host echte OS-Threads ausführen kann. PHP kann das nicht (ohne `pcntl_fork`, das nicht auf jedem Host verfügbar ist).

Phasis simuliert einen einzelnen Agenten – `Atomics.wait` gibt sofort „not-equal“ oder „timed-out“ zurück, `notify` gibt immer 0 zurück. Damit bestehen alle test262-Tests, die mit einem einzelnen Agenten laufen (Eingabevalidierung, Fehlerpfade, wirkungslose notify-Aufrufe); das umfasst 376 von 376 Atomics-Tests.

Tests, die tatsächlich zwei nebenläufige Agenten erfordern, die einander beobachten, werden nicht unterstützt. Für echte Parallelität kannst du eine Worker-Warteschlange auf Ebene von PHP verwenden (Redis, Beanstalkd, …).

## Realm-Semantik

`ShadowRealm` ist implementiert, aber jedes untergeordnete Realm läuft im selben PHP-Prozess wie der Host. Host-Funktionen können Referenzen zwischen Realms weitergeben, wenn du nicht darauf achtest, den Code von PHP abzuschirmen. Die Spezifikation erlaubt das; V8 erzwingt eine strengere Isolation durch separate v8::Isolate-Instanzen.

`createRealm()` (test262-Host-Hook) erstellt intern ein neues `Phasis\Engine` und bindet die Standardbibliothek ein.

## Wahl der Regex-Engine

Phasis verwendet PCRE2 von PHP als primäres Regex-Backend und einen eigenen Matcher für Fälle, die PCRE2 nicht exakt verarbeiten kann (Lookbehind mit Captures, quantifizierte Gruppen mit Reset, bestimmte Semantiken von `/v`-Flags). Der eigene Matcher ist langsamer als PCRE2 und kommt nur zum Einsatz, wenn der Dispatch ein inkompatibles Muster erkennt.

Eine bemerkenswerte Folge: PCRE2 kann eine andere Tabelle für Groß- und Kleinschreibung verwenden als die ICU-Version von V8, besonders bei älteren Linux-Distributionen (Ubuntu 22.04 liefert ICU 70 mit; Phasis bündelt eine ICU-76+-Tabelle zur Fallfaltung, um Abweichungen des Hosts bei `/iu`-Mustern auszugleichen).

## Speichermodell

Die GC von PHP mit Referenzzählung unterscheidet sich von V8s Tracing-Collector. Von Host-Closures erfasste PHP-Objekte bleiben so lange erhalten, wie die Engine diese Closures hält; Zyklen zwischen ihnen werden erst aufgeräumt, wenn `Engine` zerstört wird. Verwende `WeakMap` / `WeakRef` für Caches, die nicht dauerhaft erhalten bleiben sollen.

`process.memoryUsage()` und ähnliche V8-spezifische Introspektions-APIs sind nicht implementiert.

## Modullader

Der ES-Modullader löst relative Imports anhand des Dateisystems auf, versteht aber keine Konventionen von Bundlern:

- Keine `node_modules`-Auflösung.
- Keine `package.json`-`exports`-Map.
- Keine Ergänzung von Dateiendungen (du musst `import './foo.mjs'` statt `import './foo'` schreiben).
- Keine HTTP-Imports.

Das entspricht der reinen ECMAScript-Spezifikation, nicht aber dem Verhalten von Node. Es gibt keinen Hook für einen benutzerdefinierten Modul-Resolver. Um npm-Pakete zu verwenden, bündle sie mit einem Tool wie esbuild zu einem einzelnen Skript oder Modul, bevor du es an Phasis übergibst.

## Wasm

`WebAssembly` ist nicht implementiert. Es gibt keine PHP-Wasm-Laufzeit, an die eine Bindung möglich wäre.

## Browser-APIs, die wir auslassen

Phasis enthält das vollständige **Web Platform Pack** (`URL`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`, `structuredClone`, `performance`, `DOMException`), das vollständige **Fetch Pack** (`fetch`, `Request`, `Response`, `Headers`, `Body`, `AbortController`/`AbortSignal`, `Blob`/`File`, `FormData`, `EventTarget`/`Event`, vollständige WHATWG Streams, `navigator`), außerdem `crypto` (`getRandomValues`, `randomUUID`, vollständiges `SubtleCrypto`: Digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), `WebSocket` (Konstruktor + RFC-6455-Frame-Codec, austauschbarer Transport), `XMLHttpRequest` (auf dem Fetch-Transport aufbauend) und eine echte Event-Loop (`setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `queueMicrotask`, `AsyncContext`). Siehe [Web APIs](https://phasis.inline0.dev/de/docs/compatibility/web-apis).

Was *nicht* enthalten ist:

- `window`, `document`, der DOM-Baum – Phasis ist kein Browser.
- `localStorage`, `sessionStorage`, `IndexedDB` – Aufgaben des Hosts; der Embedder ist für die Persistenz zuständig.
- `Worker`, `SharedWorker`, `MessageChannel` – erfordern echte OS-Threads, die PHP nicht bietet.
- Service Workers, Push API, Benachrichtigungen, BroadcastChannel – außerhalb eines Browsers irrelevant.

## Node-Globals

`process`, `Buffer`, `__dirname`, `__filename`, `require()` – keines davon ist vorhanden. Das sind Konventionen der Node-Hostumgebung, keine Sprachfunktionen.

Wenn du Node-Code portierst, ersetze `require('foo')` durch `import 'foo'`, tausche `process.env.X` gegen ein an den Host gebundenes `env.X` aus und übergib gleichwertige Pfade für `__dirname` aus PHP.

## Dezimalgenauigkeit

ECMAScript-Zahlen sind IEEE-754-Doubles. Bei Dezimalrechnungen mit mehr als 15 signifikanten Stellen geht Genauigkeit verloren, genau wie bei jeder anderen JS-Engine. Verwende `BigInt` für exakte Ganzzahlrechnung oder eine JS-Dezimalbibliothek, wenn du exakte Bruchrechnungen brauchst.

PHPs `bcmath` wird intern für `BigInt` verwendet; der einzige echte Unterschied zu V8 ist, dass sehr große BigInt-Operationen in PHP langsamer sind als in V8s C++-Implementierung. Die numerische Korrektheit ist identisch.
