Přejít k obsahu

Známá omezení

Cílem Phasis je chovat se stejně jako V8 ve všech pozorovatelných testech specifikace. Tato stránka uvádí místa, kde se v praxi tato shoda vytrácí — obvykle kvůli zásadním rozdílům mezi interpretem PHP, který prochází strom, a strojem v C++ kompilovaným pomocí JIT.

Výkonnostní strop

Stroj prochází syntaktický strom, využívá také příležitostný bajtkódový VM a transpiler JsToPhp, který převádí těla s převahou čísel a lokálních proměnných (včetně tvarů obj.method(), new Ctor() a this.member) na nativní uzávěry PHP, které JIT s trasováním z PHP 8.5 může zkompilovat do strojového kódu. Většina horkých cest vykonávání probíhá uvnitř přepínací smyčky VM nebo přímo v kódu PHP zkompilovaném JIT, nikoli procházením AST. Každá instrukce VM ale stále nese náklady na PHP, a každý tvar, který JsToPhp zatím nepodporuje, se vrací k pomalejší VM. U úloh omezených rychlostí vykonávání je strop přibližně 100× pomalejší než V8.

U úloh využívajících vložený stroj — spouštění logiky dodané uživatelem nad daty PHP, kanálů pro transformaci obsahu a pravidel ověřování — tento strop obvykle nevadí. V8 trvá 100 ms; Phasis trvá 10 s; obojí je výrazně pod časovým limitem požadavku. Další zmenšení rozdílu by vyžadovalo rozšířit JsToPhp o více tvarů (odvozování typů parametrů, převod await / yield*) nebo generovat přímo opkódy opcache místo zprostředkování přes eval(). Viz Srovnávací testy § Plán dalšího vývoje.

Souběh více agentů

Model SharedArrayBuffer + Atomics.wait + postMessage v JavaScript předpokládá, že hostitelské prostředí může spouštět skutečná vlákna operačního systému. PHP to nedokáže (bez pcntl_fork, které není dostupné v každém hostitelském prostředí).

Phasis simuluje jediného agenta — Atomics.wait okamžitě vrací „not-equal“ nebo „timed-out“, notify vždy vrací 0. Projdou tak všechny testy test262 pro jednoho agenta (ověřování vstupu, chybové cesty, notifikace bez účinku), což zahrnuje 376 z 376 testů Atomics.

Testy, které vyžadují, aby se dva souběžní agenti navzájem pozorovali, nejsou podporovány. Pro skutečný paralelismus použijte frontu workerů na úrovni PHP (Redis, Beanstalkd, …).

Sémantika realmů

ShadowRealm je implementováno, ale každá podřízená realm běží ve stejném procesu PHP jako hostitel. Funkce hostitele mohou mezi realmami předávat reference, pokud nebudete pečlivě izolovat kód PHP. Specifikace to umožňuje; V8 vynucuje přísnější izolaci pomocí samostatných instancí v8::Isolate.

createRealm() (testovací hook hostitele test262) interně vytvoří novou instanci Phasis\Engine a propojí standardní knihovnu.

Volba regexového enginu

Phasis používá PCRE2 z PHP jako hlavní backend pro regexy a pro případy, které PCRE2 nedokáže přesně zpracovat, používá vlastní porovnávač (lookbehind se zachycenými skupinami, kvantifikované skupiny s resetem a určitou sémantiku příznaku /v). Vlastní porovnávač je pomalejší než PCRE2 a používá se pouze tehdy, když dispečer rozpozná nekompatibilní vzor.

Významným důsledkem je, že PCRE2 může používat jinou tabulku převodu velikosti písmen než verze ICU v V8, zejména ve starších distribucích Linux (Ubuntu 22.04 obsahuje ICU 70; Phasis přibaluje tabulku převodu velikosti písmen z ICU 76+, která potlačí rozdíly verzí hostitele u vzorů /iu).

Model správy paměti

Správce paměti PHP založený na počítání referencí se liší od trasovacího správce V8. Objekty PHP zachycené v uzávěrech hostitele zůstávají naživu, dokud je engine drží; cykly mezi nimi se uvolní až po zničení Engine. Pro mezipaměti, které nemají objekty udržovat naživu, použijte WeakMap / WeakRef.

process.memoryUsage() a podobná introspekční rozhraní API specifická pro V8 nejsou implementována.

Načítání modulů

Načítač modulů ES řeší relativní importy podle souborového systému, ale nerozumí konvencím bundlerů:

  • Bez rozlišení node_modules.
  • Bez mapy package.json exports.
  • Bez odvozování přípon souborů (musíte napsat import './foo.mjs', nikoli import './foo').
  • Bez importů HTTP.

To odpovídá základní specifikaci ECMAScript, ale ne chování Node. Neexistuje hook pro vlastní resolver modulů. Chcete-li používat balíčky npm, před předáním do Phasis je pomocí nástroje, jako je esbuild, sbalte do jediného skriptu nebo modulu.

Wasm

WebAssembly není implementováno. Není k dispozici žádné běhové prostředí wasm PHP, na které by se dalo navázat.

Webová API dostupná pouze v prohlížeči, která vynecháváme

Phasis obsahuje kompletní Web Platform Pack (URL, TextEncoder/TextDecoder, atob/btoa, structuredClone, performance, DOMException), kompletní Fetch Pack (fetch, Request, Response, Headers, Body, AbortController/AbortSignal, Blob/File, FormData, EventTarget/Event, kompletní WHATWG Streams, navigator), dále crypto (getRandomValues, randomUUID, kompletní SubtleCrypto: digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), WebSocket (konstruktor + kodek rámců RFC 6455, vyměnitelný přenos), XMLHttpRequest (založené na přenosové vrstvě fetch) a skutečnou smyčku událostí (setTimeout, setInterval, clearTimeout, clearInterval, queueMicrotask, AsyncContext). Viz Webová API.

Co není součástí:

  • window, document, strom DOM — Phasis není prohlížeč.
  • localStorage, sessionStorage, IndexedDB — záležitosti hostitele; za uchovávání dat odpovídá vložená aplikace.
  • Worker, SharedWorker, MessageChannel — vyžadují skutečná vlákna operačního systému, která PHP nenabízí.
  • Service Workers, Push API, Notifications, BroadcastChannel — mimo prohlížeč nemají využití.

Globální proměnné Node

process, Buffer, __dirname, __filename, require() — neexistuje ani jedna z nich. Jde o konvence hostitelského prostředí Node, nikoli o vlastnosti jazyka.

Při portování kódu z Node nahraďte require('foo') za import 'foo', vyměňte process.env.X za env.X navázané na hostitele a předejte cesty ekvivalentní __dirname z PHP.

Přesnost desetinných čísel

Čísla ECMAScript jsou 64bitová čísla s pohyblivou řádovou čárkou IEEE 754. Desetinné výpočty s více než 15 platnými číslicemi ztrácejí přesnost stejně jako v každém jiném enginu JS. Pro přesnou celočíselnou aritmetiku použijte BigInt; potřebujete-li přesné výpočty se zlomky, použijte desetinnou knihovnu JS.

PHP interně používá bcmath pro BigInt; jediným skutečným rozdílem oproti V8 je, že operace s velmi velkými hodnotami bigint jsou v PHP pomalejší než v implementaci V8 v C++. Číselné výsledky jsou stejně přesné.