
# 알려진 제한 사항

Phasis은 관찰 가능한 모든 명세 테스트에서 V8과 동일하게 동작하는 것을 목표로 합니다. 이 페이지에서는 실제 사용에서 그 동일성이 깨지는 부분을 설명합니다. 대개 트리를 순회하는 PHP 인터프리터와 JIT 컴파일되는 C++ 엔진 사이의 근본적인 차이 때문입니다.

## 성능 상한

이 엔진은 트리 워커와 기회주의적 바이트코드 VM, 그리고 JsToPhp 트랜스파일러로 구성됩니다. 이 트랜스파일러는 숫자 연산이나 로컬 변수 사용이 많은 본문(`obj.method()`, `new Ctor()`, `this.member` 형태 포함)을 네이티브 PHP 클로저로 변환하고, PHP 8.5의 추적 JIT가 이를 기계어로 컴파일할 수 있습니다. 대부분의 핫 디스패치는 VM의 스위치 루프 내부나 JIT 컴파일된 PHP 안에서 직접 처리되므로 AST를 순회하지 않습니다. 하지만 VM 연산 코드마다 여전히 PHP 디스패치 비용이 들고, JsToPhp가 아직 처리하지 못하는 형태는 더 느린 VM으로 되돌아갑니다. 디스패치가 병목인 작업의 성능 상한은 V8보다 약 **100배 느린 수준**입니다.

임베딩 작업, 예를 들어 사용자가 제공한 로직으로 PHP 데이터를 처리하는 일, 콘텐츠 변환 파이프라인, 유효성 검사 규칙에서는 이 상한이 문제가 되는 경우가 드뭅니다. V8은 100ms이고, Phasis는 10초이므로 둘 다 요청 시간 제한보다 훨씬 짧습니다. 격차를 더 줄이려면 JsToPhp가 더 많은 형태(매개변수 타입 추론, `await` / `yield*` 변환)를 처리하도록 하거나 `eval()`를 거치지 않고 opcache opcode를 직접 출력해야 합니다. [벤치마크 § 로드맵](https://phasis.inline0.dev/ko/docs/advanced/benchmarks#roadmap)을 참조하세요.

## 멀티 에이전트 동시성

JavaScript의 `SharedArrayBuffer` + `Atomics.wait` + `postMessage` 모델은 호스트가 실제 OS 스레드를 실행할 수 있다고 가정합니다. PHP은 그렇게 할 수 없습니다(모든 호스트에서 사용할 수 없는 `pcntl_fork` 없이는 불가능합니다).

Phasis은 단일 에이전트를 시뮬레이션합니다. `Atomics.wait`은 즉시 "not-equal" 또는 "timed-out"을 반환하고, `notify`는 항상 0을 반환합니다. 단일 에이전트로 실행되는 모든 test262 테스트(입력 유효성 검사, 오류 경로, 알림 없음)는 통과하며, 이는 376 Atomics 테스트의 376을 차지합니다.

서로를 관찰하는 두 에이전트의 동시 실행이 필요한 테스트는 지원하지 않습니다. 실제 병렬 처리가 필요하면 PHP 수준에서 작업자 큐(Redis, Beanstalkd, …)를 사용하세요.

## Realm 의미론

`ShadowRealm`은 구현되어 있지만 각 하위 realm은 호스트와 동일한 PHP 프로세스에서 실행됩니다. 호스트 함수가 realm 사이에 참조를 누출할 수 있으므로 PHP 코드를 방화벽으로 격리해야 합니다. 명세는 이를 허용하지만 V8은 별도의 v8::Isolate 인스턴스로 더 엄격하게 격리합니다.

`createRealm()`(test262 호스트 훅)은 내부적으로 새 `Phasis\Engine`를 만들고 표준 라이브러리를 연결합니다.

## 정규식 엔진 선택

Phasis은 기본 정규식 백엔드로 PHP의 PCRE2를 사용하고, PCRE2가 정확히 처리하지 못하는 경우(캡처가 포함된 후방 탐색, 리셋이 있는 반복 그룹, 특정 `/v` 플래그 의미론)를 위한 맞춤형 매처를 사용합니다. 맞춤형 매처는 PCRE2보다 느리며, 디스패치에서 호환되지 않는 패턴이 감지될 때만 사용됩니다.

주목할 만한 결과는 PCRE2의 대소문자 접기 테이블이 V8의 ICU 버전과 다를 수 있다는 점입니다. 특히 오래된 Linux 배포판에서 그렇습니다(Ubuntu 22.04에는 ICU 70이 포함되고, Phasis은 `/iu` 패턴에서 호스트 환경에 따른 차이를 덮어쓰도록 ICU 76 이상의 접기 테이블을 포함합니다).

## 메모리 모델

PHP의 참조 카운팅 GC는 V8의 추적 수집기와 다릅니다. 호스트 클로저가 캡처한 PHP 객체는 엔진이 해당 클로저를 보유하는 동안 유지되며, 객체 간 순환 참조는 `Engine`이 파괴될 때까지 정리되지 않습니다. 캐시에서 유지하고 싶지 않은 항목에는 `WeakMap` / `WeakRef`를 사용하세요.

`process.memoryUsage()` 및 이와 유사한 V8 전용 내부 검사 API는 구현되어 있지 않습니다.

## 모듈 로더

ES 모듈 로더는 파일 시스템을 기준으로 상대 경로 import를 확인하지만 번들러 규칙은 이해하지 못합니다:

- `node_modules` 해석을 지원하지 않습니다.
- `package.json` `exports` 맵을 지원하지 않습니다.
- 파일 확장자를 추론하지 않습니다(`import './foo'`가 아니라 `import './foo.mjs'`라고 작성해야 합니다).
- HTTP import를 지원하지 않습니다.

이는 기본 ECMAScript 명세에는 부합하지만 Node의 동작과는 다릅니다. 사용자 지정 모듈 확인을 위한 훅은 없습니다. npm 패키지를 사용하려면 esbuild 같은 도구로 단일 스크립트나 모듈로 번들링한 뒤 Phasis에 전달하세요.

## Wasm

`WebAssembly`은 구현되어 있지 않습니다. 연결할 PHP wasm 런타임이 없습니다.

## 지원하지 않는 브라우저 전용 웹 API

Phasis은 전체 **Web Platform Pack**(`URL`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`, `structuredClone`, `performance`, `DOMException`), 전체 **Fetch Pack**(`fetch`, `Request`, `Response`, `Headers`, `Body`, `AbortController`/`AbortSignal`, `Blob`/`File`, `FormData`, `EventTarget`/`Event`, 전체 WHATWG Streams, `navigator`), 그리고 `crypto`(`getRandomValues`, `randomUUID`, 전체 `SubtleCrypto`: digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), `WebSocket`(생성자 + RFC 6455 프레임 코덱, 교체 가능한 전송 계층), `XMLHttpRequest`(fetch 전송 계층 기반), 실제 이벤트 루프(`setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `queueMicrotask`, `AsyncContext`)를 제공합니다. [웹 API](https://phasis.inline0.dev/ko/docs/compatibility/web-apis)를 참조하세요.

제공하지 않는 기능:

- `window`, `document`, DOM 트리 — Phasis은 브라우저가 아닙니다.
- `localStorage`, `sessionStorage`, `IndexedDB` — 호스트 측 기능이며 영속성은 임베더가 담당합니다.
- `Worker`, `SharedWorker`, `MessageChannel` — 실제 OS 스레드가 필요하지만 PHP은 이를 제공하지 않습니다.
- Service Workers, Push API, Notifications, BroadcastChannel — 브라우저 밖에서는 쓸모가 없습니다.

## Node 전역 객체

`process`, `Buffer`, `__dirname`, `__filename`, `require()` — 이 중 어느 것도 제공되지 않습니다. 이는 언어 기능이 아니라 Node 호스트의 규칙입니다.

Node 코드를 포팅하는 경우 `require('foo')`을 `import 'foo'`으로 바꾸고, `process.env.X`를 호스트에 연결된 `env.X`로 교체한 뒤, PHP에서 `__dirname`에 해당하는 경로를 전달하세요.

## 소수 정밀도

ECMAScript 숫자는 IEEE 754 배정밀도 부동소수점 수입니다. 유효 숫자가 15자리를 넘는 십진 연산은 다른 모든 JS 엔진과 마찬가지로 정밀도를 잃습니다. 정확한 정수 연산에는 `BigInt`을 사용하고, 정확한 소수 연산이 필요하면 JS 십진 라이브러리를 사용하세요.

PHP의 `bcmath`은 내부적으로 `BigInt`에 사용됩니다. V8과 실제로 다른 점은 매우 큰 bigint 연산이 V8의 C++ 구현보다 PHP에서 느리다는 것입니다. 수치 정확성은 동일합니다.
