
# Tunnetut rajoitukset

Phasis pyrkii toimimaan kaikissa havaittavissa olevissa spesifikaatiotesteissä samalla tavalla kuin V8. Tällä sivulla luetellaan kohdat, joissa yhtäläisyys ei käytännössä enää päde — yleensä puuta läpikäyvän PHP-tulkin ja JIT-käännetyn C++-moottorin perustavanlaatuisten erojen vuoksi.

## Suorituskyvyn yläraja

Moottori käy puuta läpi, käyttää tilaisuuden mukaan tavukoodia suorittavaa VM:ää ja sisältää JsToPhp-transpilerin, joka muuntaa numeeriset tai paikallisiin muuttujiin painottuvat lohkot (mukaan lukien `obj.method()`-, `new Ctor()`- ja `this.member`-muodot) natiiveiksi PHP-sulkeumiksi, jotka PHP 8.5:n jäljityspohjainen JIT voi kääntää konekoodiksi. Suurin osa kuumien toimintojen suorituksesta tapahtuu VM:n switch-silmukan sisällä tai suoraan JIT-käännetyssä PHP-koodissa — ei AST:tä läpikäymällä — mutta jokaisesta VM-opkoodista maksetaan silti PHP-kutsun kustannus, ja kaikki muodot, joita JsToPhp ei vielä käsittele, siirtyvät hitaampaan VM:ään. Kutsujen suorituskyvyn rajoittamissa kuormissa yläraja on suunnilleen **100× hitaampi kuin V8**.

Upotuskäytössä — kun suoritetaan käyttäjän antamaa logiikkaa PHP-datalla, sisältömuunnosputkia tai validointisääntöjä — ylärajalla on harvoin merkitystä. V8 kestää 100 ms; Phasis kestää 10 s; molemmat jäävät selvästi pyynnön aikakatkaisun alle. Kuilun kaventaminen edellyttäisi, että JsToPhp oppii käsittelemään lisää muotoja (parametrien tyyppipäätelmät, `await`- ja `yield*`-muotojen muunnos) tai että opcache-opkoodit tuotettaisiin suoraan eikä `eval()`n kautta. Katso [Vertailumittaukset § Suunnitelma](https://phasis.inline0.dev/fi/docs/advanced/benchmarks#roadmap).

## Rinnakkaisuus usean agentin kesken

JavaScriptn `SharedArrayBuffer` + `Atomics.wait` + `postMessage` -malli olettaa, että isäntäympäristö voi suorittaa oikeita käyttöjärjestelmäsäikeitä. PHP ei pysty siihen ilman `pcntl_fork`, jota ei ole käytettävissä kaikissa isäntäympäristöissä.

Phasis simuloi yhtä agenttia — `Atomics.wait` palauttaa heti arvon "not-equal" tai "timed-out", ja `notify` palauttaa aina arvon 0. Tämä läpäisee kaikki yksittäisellä agentilla suoritettavat test262-testit (syötteen validointi, virhetilanteet ja tyhjä notify-kutsu), jotka kattavat 376 Atomics-testeistä 376.

Testit, jotka edellyttävät kahden samanaikaisen agentin havaitsevan toisensa, eivät ole tuettuja. Käytä PHP-tason työjonon rinnalla (Redis, Beanstalkd, …) aitoa rinnakkaisuutta varten.

## Realm-semanttiikka

`ShadowRealm` on toteutettu, mutta jokainen lapsirealm toimii samassa PHP-prosessissa kuin isäntäympäristö. Isäntäympäristön funktiot voivat vuotaa viitteitä realmien välillä, ellet pidä huolta siitä, että PHP-koodi pysyy eristettynä. Spesifikaatio sallii tämän; V8 valvoo tiukempaa eristystä erillisillä v8::Isolate-instansseilla.

`createRealm()` (test262-isäntäkytkentä) luo sisäisesti uuden `Phasis\Engine`-instanssin ja yhdistää standardikirjaston siihen.

## Säännöllisten lausekkeiden moottorin valinta

Phasis käyttää PHPn PCRE2:ta ensisijaisena säännöllisten lausekkeiden taustamoottorina sekä mukautettua täsmäytintä tapauksissa, joita PCRE2 ei voi käsitellä täsmälleen oikein (sieppauksia sisältävä lookbehind, nollauksen sisältävät toistetut ryhmät ja tietyt `/v`-lippujen semantiikat). Mukautettu täsmäytin on PCRE2:ta hitaampi, ja sitä käytetään vain, kun käsittely tunnistaa yhteensopimattoman kuvion.

Huomattava seuraus on, että PCRE2:n kirjainkoon muunnostaulukko voi poiketa V8n ICU-versiosta etenkin vanhemmissa Linux-jakeluversioissa (Ubuntu 22.04 sisältää ICU 70:n; Phasis sisältää ICU 76+:n muunnostaulukon, joka ohittaa isäntäympäristön erot `/iu`-kuvioissa).

## Muistimalli

PHPn viitelaskentaan perustuva roskienkeruu eroaa V8n jäljittävästä kerääjästä. Isäntäympäristön sulkeumien kaappaamat PHP-objektit pysyvät elossa niin kauan kuin moottori pitää kyseiset sulkeumat hallussaan, eikä niiden välisiä syklejä kerätä ennen kuin `Engine` tuhotaan. Käytä `WeakMap`- tai `WeakRef`-rakennetta välimuisteille, joita et halua pitää elossa.

`process.memoryUsage()`- ja vastaavia V8-kohtaisia introspektio-API:eja ei ole toteutettu.

## Moduulien lataaja

ES-moduulien lataaja ratkaisee suhteelliset tuonnit tiedostojärjestelmän perusteella, mutta ei ymmärrä paketoijien käytäntöjä:

- Ei `node_modules`-ratkaisua.
- Ei `package.json`n `exports`-karttaa.
- Tiedostopäätettä ei päätellä (sinun on kirjoitettava `import './foo.mjs'`, ei `import './foo'`).
- Ei HTTP-tuonteja.

Tämä vastaa paljasta ECMAScript-määritystä mutta ei Noden toimintaa. Mukautetulle moduulien ratkaisijalle ei ole kytkentäpistettä. Jos haluat käyttää npm-paketteja, paketoi ne esimerkiksi esbuild-työkalulla yhdeksi komentosarjaksi tai moduuliksi ennen sen välittämistä Phasislle.

## Wasm

`WebAssembly` ei ole toteutettu. Sidottavaksi ei ole käytettävissä PHP-wasm-ajoympäristöä.

## Selaimessa käytettävät Web API:t, joita emme sisällytä

Phasis sisältää koko **Web Platform Pack** -paketin (`URL`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`, `structuredClone`, `performance`, `DOMException`), koko **Fetch Pack** -paketin (`fetch`, `Request`, `Response`, `Headers`, `Body`, `AbortController`/`AbortSignal`, `Blob`/`File`, `FormData`, `EventTarget`/`Event`, täydellisen WHATWG Streams -toteutuksen ja `navigator`n) sekä `crypto`n (`getRandomValues`, `randomUUID`, täydellisen `SubtleCrypto`n: digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), `WebSocket`n (konstruktori ja RFC 6455 -kehysmuunnin, vaihdettava siirtotapa), `XMLHttpRequest`n (Fetch-siirtotavan päälle rakennettu) sekä todellisen tapahtumasilmukan (`setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `queueMicrotask`, `AsyncContext`). Katso [Web API:t](https://phasis.inline0.dev/fi/docs/compatibility/web-apis).

Mitä pakettiin *ei* sisälly:

- `window`, `document` ja DOM-puu — Phasis ei ole selain.
- `localStorage`, `sessionStorage` ja `IndexedDB` — isäntäympäristön vastuulla; upottaja vastaa pysyvästä tallennuksesta.
- `Worker`, `SharedWorker` ja `MessageChannel` — edellyttävät oikeita käyttöjärjestelmäsäikeitä, joita PHP ei tarjoa.
- Service Workers, Push API, ilmoitukset ja BroadcastChannel — tarpeettomia selaimen ulkopuolella.

## Node-yleismuuttujat

`process`, `Buffer`, `__dirname`, `__filename` ja `require()` — näitäkään ei ole. Ne ovat Node-isäntäympäristön käytäntöjä, eivät kielen ominaisuuksia.

Jos siirrät Node-koodia, korvaa `require('foo')` arvolla `import 'foo'`, vaihda `process.env.X` isäntäympäristöön sidottuun `env.X`-arvoon ja välitä `__dirname`-vastaavat polut PHPsta.

## Desimaalitarkkuus

ECMAScriptin luvut ovat IEEE 754 -liukulukuja kaksinkertaisella tarkkuudella. Yli 15 merkitsevän numeron desimaalilaskenta menettää tarkkuutta aivan kuten kaikissa muissakin JS-moottoreissa. Käytä `BigInt`tä täsmälliseen kokonaislukulaskentaan tai JS-desimaalikirjastoa, jos tarvitset tarkkaa murtolukulaskentaa.

PHPn `bcmath`tä käytetään sisäisesti `BigInt`n toteutukseen; ainoa todellinen ero V8een verrattuna on se, että erittäin suuret bigint-operaatiot ovat hitaampia PHPssä kuin V8n C++-toteutuksessa. Numeerinen oikeellisuus on sama.
