İçeriğe geç

Bilinen sınırlamalar

Phasis, gözlemlenebilir tüm spesifikasyon testlerinde V8 ile aynı şekilde davranmayı hedefler. Bu sayfada, ağaç dolaşan bir PHP yorumlayıcı ile JIT derlenen bir C++ motoru arasındaki temel farklılıklardan kaynaklanan, bu eşitliğin pratikte geçerli olmadığı noktalar listelenir.

Performans sınırı

Motor; fırsatçı bir bytecode VM'i ve sayısal, yerel değişken ağırlıklı gövdeleri (obj.method(), new Ctor() ve this.member biçimleri dahil) yerel PHP closure'larına dönüştüren bir JsToPhp transpiler'ı bulunan, ağacı dolaşan bir yorumlayıcıdır. PHP 8.5'in izleme JIT'i bu closure'ları makine koduna derleyebilir. Sıcak çağrıların çoğu AST üzerinde dolaşmak yerine VM'in switch döngüsünde veya doğrudan JIT derlemeli PHP içinde gerçekleşir; ancak her VM opcode'u yine de PHP çağrı maliyetine tabidir ve JsToPhp'in henüz desteklemediği biçimler daha yavaş VM'e geri döner. Çağrı maliyetine bağlı iş yüklerinde performans sınırı yaklaşık V8'den ~100× daha yavaştır.

Gömülü kullanım senaryolarında — PHP verileri üzerinde kullanıcı tarafından sağlanan mantığı çalıştırma, içerik dönüştürme işlem hatları ve doğrulama kuralları gibi — bu sınır nadiren önem taşır. V8 100 ms, Phasis ise 10 s sürer; ikisi de istek zaman aşımının oldukça altındadır. Aradaki farkı daha da azaltmak için JsToPhp'e daha fazla biçim öğretmek (parametre türü çıkarımı, await / yield* dönüştürme) veya opcache opcode'larını eval() üzerinden değil doğrudan üretmek gerekir. Bkz. Kıyaslamalar § Yol haritası.

Çoklu ajan eşzamanlılığı

JavaScript'ın SharedArrayBuffer + Atomics.wait + postMessage modeli, ana makinenin gerçek işletim sistemi iş parçacıklarını çalıştırabildiğini varsayar. PHP bunu yapamaz (her ana makinede bulunmayan pcntl_fork olmadan).

Phasis tek bir ajanı simüle eder: Atomics.wait hemen "not-equal" veya "timed-out" döndürür, notify ise her zaman 0 döndürür. Böylece tek ajanla çalışan her test262 testi (girdi doğrulama, hata yolları, etkisiz notify) geçilir; bu da 376 Atomics testlerinin 376 kadarını kapsar.

Birbirini gözlemleyen iki eşzamanlı ajanı gerçekten gerektiren testler desteklenmez. Gerçek paralellik için PHP düzeyinde (Redis, Beanstalkd, …) bir çalışan kuyruğu kullanın.

Realm semantiği

ShadowRealm uygulanmıştır ancak her alt realm, ana makineyle aynı PHP sürecinde çalışır. PHP kodunu yalıtılmış tutmaya dikkat etmezseniz ana makine işlevleri realm'ler arasında referans sızdırabilir. Spesifikasyon buna izin verir; V8 ise ayrı v8::Isolate örnekleriyle daha katı yalıtım uygular.

createRealm() (test262 ana makine kancası), içeride yeni bir Phasis\Engine oluşturur ve standart kütüphaneyi köprü üzerinden aktarır.

Regex motoru tercihi

Phasis, birincil regex arka ucu olarak PHP'ın PCRE2'sini kullanır ve PCRE2'nin tam olarak işleyemediği durumlar için özel bir eşleştirici sunar (yakalama gruplu lookbehind, sıfırlama içeren nicelemeli gruplar, belirli /v bayrağı semantikleri). Özel eşleştirici PCRE2'den yavaştır ve yalnızca dağıtım uyumsuz bir desen algıladığında kullanılır.

Bunun kayda değer bir sonucu şudur: PCRE2'nin büyük/küçük harf dönüştürme tablosu, özellikle eski Linux dağıtımlarında (Ubuntu 22.04, ICU 70'i içerir; Phasis ise /iu desenlerinde ana makine sürümü farklılıklarını geçersiz kılmak için ICU 76+ dönüşüm tablosunu paketler) V8'ın ICU sürümündekinden farklı olabilir.

Bellek modeli

PHP'ın referans sayımlı GC'si, V8'ın izleme tabanlı çöp toplayıcısından farklıdır. Ana makine closure'larının yakaladığı PHP nesneleri, motor bu closure'ları tuttuğu sürece bellekte kalır; aralarındaki döngüler de Engine yok edilene kadar toplanmaz. Bellekte kalmasını istemediğiniz önbellekler için WeakMap / WeakRef kullanın.

process.memoryUsage() ve benzeri V8'a özgü içgözlem API'leri uygulanmamıştır.

Modül yükleyici

ES modül yükleyicisi göreli içe aktarmaları dosya sistemine göre çözümler ancak paketleyici kurallarını anlamaz:

  • node_modules çözümlemesi yok.
  • package.json exports eşlemesi yok.
  • Dosya uzantısı çıkarımı yok (import './foo' değil, import './foo.mjs' yazmalısınız).
  • HTTP içe aktarmaları yok.

Bu, yalın ECMAScript spesifikasyonuyla uyumludur ancak Node'un davranışıyla uyumlu değildir. Özel bir modül çözücü için kanca bulunmaz. npm paketlerini kullanmak için esbuild gibi bir araçla bunları tek bir betik veya modül halinde paketleyip Phasis'e aktarın.

Wasm

WebAssembly uygulanmamıştır. Bağlanacak bir PHP wasm çalışma zamanı yoktur.

Atladığımız yalnızca tarayıcıda bulunan Web API'leri

Phasis; eksiksiz Web Platform Pack'i (URL, TextEncoder/TextDecoder, atob/btoa, structuredClone, performance, DOMException), eksiksiz Fetch Pack'i (fetch, Request, Response, Headers, Body, AbortController/AbortSignal, Blob/File, FormData, EventTarget/Event, eksiksiz WHATWG Streams, navigator), ayrıca crypto'yi (getRandomValues, randomUUID, eksiksiz SubtleCrypto: digest, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2), WebSocket'yı (oluşturucu + RFC 6455 çerçeve kodlayıcısı, değiştirilebilir taşıma katmanı), XMLHttpRequest'yi (fetch taşıma katmanının üzerinde) ve gerçek bir olay döngüsünü (setTimeout, setInterval, clearTimeout, clearInterval, queueMicrotask, AsyncContext) sunar. Bkz. Web API'leri.

Paketle gelmeyenler:

  • window, document ve DOM ağacı — Phasis bir tarayıcı değildir.
  • localStorage, sessionStorage, IndexedDB — ana makine tarafına ait konulardır; kalıcılıktan gömücü sorumludur.
  • Worker, SharedWorker, MessageChannel — gerçek işletim sistemi iş parçacıkları gerektirir; PHP bunları sunmaz.
  • Service Workers, Push API, Notifications, BroadcastChannel — tarayıcı dışında anlamlı değildir.

Node global'leri

process, Buffer, __dirname, __filename, require() — bunların hiçbiri de mevcut değildir. Bunlar dil özellikleri değil, Node ana makine kurallarıdır.

Node kodunu başka bir ortama taşıyorsanız require('foo') yerine import 'foo' kullanın, process.env.X yerine ana makineye bağlı bir env.X koyun ve PHP konumundan __dirname eşdeğeri yollar aktarın.

Ondalık hassasiyeti

ECMAScript sayıları IEEE 754 çift duyarlıklı sayılardır. 15'ten fazla anlamlı basamağa sahip ondalık işlemler, diğer tüm JS motorlarında olduğu gibi hassasiyet kaybeder. Kesin tamsayı işlemleri için BigInt kullanın; kesin kesirli işlemler gerekiyorsa bir JS ondalık kütüphanesi kullanın.

PHP'ın bcmath'i, BigInt için dahili olarak kullanılır; V8 ile tek gerçek fark, çok büyük bigint işlemlerinin V8'ın C++ uygulamasına kıyasla PHP'te daha yavaş olmasıdır. Sayısal doğruluk aynıdır.