
# Limites connues

Phasis vise à se comporter exactement comme V8 pour chaque test observable de la spécification. Cette page décrit les cas où cette équivalence s’arrête en pratique — généralement en raison des différences fondamentales entre un interpréteur PHP qui parcourt l’arbre et un moteur C++ compilé par JIT.

## Plafond de performances

Le moteur parcourt l’arbre et dispose d’une machine virtuelle à bytecode opportuniste et d’un transpilateur JsToPhp qui convertit les corps à forte utilisation de nombres ou de variables locales (y compris les formes `obj.method()`, `new Ctor()` et `this.member`) en fermetures natives PHP que le JIT à traces de PHP 8.5 peut compiler en code machine. La plupart des opérations intensives s’exécutent dans la boucle switch de la machine virtuelle ou directement dans PHP compilé par JIT, et non en parcourant l’AST ; toutefois, chaque opcode de la machine virtuelle entraîne toujours le coût de distribution de PHP, et toute forme que JsToPhp ne sait pas encore gérer repasse par la machine virtuelle plus lente. Pour les charges dominées par la distribution, le plafond est d’environ **100× plus lent que V8**.

Pour les charges embarquées — exécuter une logique fournie par l’utilisateur sur des données PHP, des pipelines de transformation de contenu ou des règles de validation — ce plafond compte rarement. V8 prend 100 ms ; Phasis prend 10 s ; les deux durées restent bien en deçà du délai d’expiration de la requête. Pour réduire davantage l’écart, il faudrait apprendre à JsToPhp davantage de formes (inférence des types de paramètres, conversion de `await` / `yield*`) ou produire directement des opcodes opcache plutôt que de passer par `eval()`. Voir [Benchmarks § Feuille de route](https://phasis.inline0.dev/fr/docs/advanced/benchmarks#roadmap).

## Concurrence multi-agent

Le modèle `SharedArrayBuffer` + `Atomics.wait` + `postMessage` de JavaScript suppose que l’hôte peut exécuter de vrais threads du système d’exploitation. PHP ne le peut pas sans `pcntl_fork`, qui n’est pas disponible sur tous les hôtes.

Phasis simule un seul agent : `Atomics.wait` renvoie immédiatement « not-equal » ou « timed-out », tandis que `notify` renvoie toujours 0. Cela réussit tous les tests test262 à agent unique (validation des entrées, cas d’erreur, notification sans effet), soit 376 des 376 tests Atomics.

Les tests qui nécessitent réellement deux agents concurrents capables de s’observer mutuellement ne sont pas pris en charge. Utilisez une file de travailleurs au niveau PHP (Redis, Beanstalkd, …) pour obtenir un véritable parallélisme.

## Sémantique des environnements globaux

`ShadowRealm` est implémenté, mais chaque environnement enfant s’exécute dans le même processus PHP que l’hôte. Les fonctions hôtes peuvent laisser fuir des références entre les environnements si vous ne veillez pas à isoler le code PHP. La spécification l’autorise ; V8 impose une isolation plus stricte au moyen d’instances v8::Isolate séparées.

`createRealm()` (hook hôte test262) crée en interne un nouvel `Phasis\Engine` et y expose la bibliothèque standard.

## Choix du moteur d’expressions régulières

Phasis utilise PCRE2 de PHP comme moteur principal d’expressions régulières, avec un moteur personnalisé pour les cas que PCRE2 ne peut pas traiter exactement (lookbehind avec captures, groupes quantifiés avec réinitialisation, certaines sémantiques d’indicateurs `/v`). Ce moteur personnalisé est plus lent que PCRE2 et n’est utilisé que lorsque la distribution détecte un motif incompatible.

Conséquence notable : la table de pliage de la casse de PCRE2 peut différer de celle de la version ICU de V8, en particulier sur les anciennes distributions Linux (Ubuntu 22.04 fournit ICU 70 ; Phasis intègre une table de pliage ICU 76+ pour neutraliser les variations de l’hôte sur les motifs `/iu`).

## Modèle mémoire

Le GC à comptage de références de PHP diffère du ramasse-miettes à traçage de V8. Les objets PHP capturés par des fermetures hôtes restent en mémoire tant que le moteur conserve ces fermetures, et les cycles entre ces objets ne sont pas libérés avant la destruction de `Engine`. Utilisez `WeakMap` / `WeakRef` pour les caches que vous ne voulez pas garder en mémoire.

Les API d’introspection propres à V8 telles que `process.memoryUsage()` ne sont pas implémentées.

## Chargeur de modules

Le chargeur de modules ES résout les imports relatifs à partir du système de fichiers, mais ne comprend pas les conventions des bundlers :

- Pas de résolution `node_modules`.
- Pas de mappage `exports` de `package.json`.
- Pas d’inférence d’extension de fichier (vous devez écrire `import './foo.mjs'`, et non `import './foo'`).
- Pas d’imports HTTP.

Cela correspond à la spécification ECMAScript sans ajouts, mais pas au comportement de Node. Il n’existe aucun hook pour personnaliser le résolveur de modules. Pour utiliser des packages npm, regroupez-les dans un seul script ou module à l’aide d’un outil comme esbuild avant de les transmettre à Phasis.

## Wasm

`WebAssembly` n’est pas implémenté. Aucun environnement d’exécution wasm PHP n’est disponible pour le prendre en charge.

## API Web réservées au navigateur ignorées

Phasis fournit l’intégralité du **Web Platform Pack** (`URL`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`, `structuredClone`, `performance`, `DOMException`), l’intégralité du **Fetch Pack** (`fetch`, `Request`, `Response`, `Headers`, `Body`, `AbortController`/`AbortSignal`, `Blob`/`File`, `FormData`, `EventTarget`/`Event`, les flux WHATWG complets, `navigator`), ainsi que `crypto` (`getRandomValues`, `randomUUID`, `SubtleCrypto` complet : digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), `WebSocket` (constructeur et codec de trames RFC 6455, transport interchangeable), `XMLHttpRequest` (superposé au transport fetch), ainsi qu’une véritable boucle d’événements (`setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `queueMicrotask`, `AsyncContext`). Voir [API Web](https://phasis.inline0.dev/fr/docs/compatibility/web-apis).

Ce qui n’est pas inclus :

- `window`, `document` et l’arbre DOM : Phasis n’est pas un navigateur.
- `localStorage`, `sessionStorage`, `IndexedDB` : des responsabilités de l’hôte ; l’intégrateur gère la persistance.
- `Worker`, `SharedWorker`, `MessageChannel` : nécessitent de vrais threads du système d’exploitation, que PHP ne fournit pas.
- Service Workers, Push API, Notifications et BroadcastChannel — inutiles en dehors d’un navigateur.

## Variables globales de Node

`process`, `Buffer`, `__dirname`, `__filename` et `require()` n’existent pas non plus. Ce sont des conventions de l’environnement hôte Node, pas des fonctionnalités du langage.

Si vous portez du code Node, remplacez `require('foo')` par `import 'foo'`, remplacez `process.env.X` par un `env.X` fourni par l’hôte et transmettez les chemins équivalents à `__dirname` depuis PHP.

## Précision décimale

Les nombres ECMAScript sont des nombres flottants IEEE 754 à double précision. Les calculs décimaux dépassant 15 chiffres significatifs perdent en précision, comme dans tous les autres moteurs JS. Utilisez `BigInt` pour des calculs entiers exacts ou une bibliothèque décimale JS pour des calculs fractionnaires exacts.

Le `bcmath` de PHP est utilisé en interne pour `BigInt` ; la seule différence notable avec V8 est que les opérations bigint de très grande taille sont plus lentes dans PHP que dans l’implémentation C++ de V8. La précision numérique est identique.
