Değer dönüştürme
PHP↔JS sınırını geçen her çağrı — setGlobal, call, JS üzerinden çağrılan bir ana makine işlevi — bir dönüştürücüden geçer:
- Ana makine değerleri motora aktarılırken PHP → JS (
setGlobal(),call()bağımsız değişkenleri, ana makine işlevlerinin dönüş değerleri). - JS değerleri geri dönerken JS → PHP. Biraz farklı kuralları olan iki yol vardır:
eval()vecall()sonuçları ile JS'ın bir ana makine işlevine ilettiği bağımsız değişkenler.
Dönüştürme kopyalama yapar. İlkel değerler ilkel değerlere eşlenir, diziler ve nesneler yeni yapılara kopyalanır, PHP çağrılabilirleri ise JS işlevleri olarak sarılır. Çağrılabilirlerin kendileri dışında hiçbir şey başvuru yoluyla paylaşılmaz.
PHP → JS
| PHP değeri | JS sonucu |
|---|---|
null |
null |
true / false |
true / false |
int |
number (IEEE 754 çift duyarlık; 2^53 üzerindeki tam sayılar hassasiyet kaybeder) |
float |
number (NaN, ±Infinity, ±0 korunur) |
string |
string (UTF-8 PHP baytları UTF-16 kod birimleri olarak yorumlanır); PHP işlevini adlandırsa bile |
liste array (anahtarlar sırayla 0, 1, 2, …) |
yeni Array, öğeler yinelemeli olarak dönüştürülür |
diğer tüm array değerleri |
yeni düz Object, değerler yinelemeli olarak dönüştürülür |
Closure, çağrılabilir nesne, [$object, 'method'] gibi çağrılabilir dizi |
PHP çağrılabilirini çağıran function |
diğer tüm nesneler, Generator, kaynak |
undefined |
Karma anahtarlı diziler (PHP'ın [0 => 'a', 'name' => 'b'] özelliği), düz nesnelere dönüşür; çünkü JS dizilerinde bitişik bir tamsayı indeks alanı bulunmalıdır.
$engine->setGlobal('list', [1, 2, 3]); // → JS Array
$engine->setGlobal('map', ['a' => 1, 'b' => 2]); // → JS Object
$engine->setGlobal('mixed', [0 => 'x', 'k' => 'v']); // → JS Object
Diziler kopyalandığından, JS değişiklikleri JS içinde kalır:
$list = [1, 2, 3];
$engine->setGlobal('list', $list);
$engine->eval('list.push(4)');
count($list); // 3
$engine->eval('list.length'); // 4
Çağrılabilir olmayan PHP nesneleri dönüştürülmez; undefined olarak gelirler (sorun #18). Önce dizilere dönüştürün; örneğin get_object_vars() kullanın veya yöntemlerini kapatmalar olarak sunun. Bkz. Paylaşılan nesneler.
JS → PHP: eval() ve call() sonuçları
| JS değeri | PHP sonucu |
|---|---|
undefined, null |
null |
boolean |
bool |
number (tam sayı, int aralığında) |
int (-0, 0 olur) |
NaN, Infinity, -Infinity |
NAN, INF, -INF |
number (diğer) |
float |
string |
string (UTF-8) |
bigint, symbol |
null |
function |
null |
Array |
liste array, öğeler yinelemeli olarak dönüştürülür |
TypedArray |
sayılardan oluşan liste array |
diğer tüm nesneler (düz nesneler, Error, Date, Map, Set, Promise, ArrayBuffer, …) |
kendi veri özelliklerini içeren ilişkisel array; erişimciler ve işlev değerli özellikler atlanır |
Son satır, durumu dahili yuvalarda bulunan nesnelerin boş bir diziye dönüştüğü anlamına gelir: new Date(0), new Map([["a", 1]]) ve Promise.resolve(5) tümü [] döndürür. Bir Error kendi message ve stack değerlerini döndürür. Kendine başvuran bir nesne, iç başvurularını null değerine dönüştürür.
$engine->eval('[1, 2, 3]'); // [1, 2, 3]
$engine->eval('({a: 1, b: 2})'); // ['a' => 1, 'b' => 2]
$engine->eval('new Uint8Array([1, 2, 3])'); // [1, 2, 3]
$engine->eval('1234567890123456789n'); // null
$engine->eval('new Date(0)'); // []
Bu değerlerden birine PHP içinde ihtiyacınız varsa, JS içinde dönüştürün:
$engine->eval('(1234567890123456789n).toString()'); // "1234567890123456789"
$engine->eval('new Date(0).toISOString()'); // "1970-01-01T00:00:00.000Z"
$engine->eval('Object.fromEntries(new Map([["a", 1]]))'); // ['a' => 1]
JS → PHP: ana makine işlevi bağımsız değişkenleri
JS'ın bir PHP ana makine işlevine ilettiği bağımsız değişkenler; ilkel değerler, diziler ve düz nesneler için aynı kuralları izler, şu farklarla:
| JS değeri | PHP argümanı |
|---|---|
TypedArray, ArrayBuffer, DataView |
motorun kendi JsValue nesnesi, dönüştürülmeden |
| nesne | erişimciler (getter'ları çalıştırılır) ve işlev değerli özellikler dahil tüm kendi özelliklerini içeren ilişkisel array |
| ok işlevi | bir array (genellikle boş) |
function anahtar sözcüğüyle tanımlanan function veya kendisine başvuran herhangi bir nesne |
dönüştürme yapılamaz: kopyalama hiç bitmez ve PHP belleği tükenir (sorun #21) |
Bir ana makine işlevinde henüz JS geri çağrısı alma yolu yoktur. Bu sınırdan işlev değil, veri geçirin.
Sayılar ve hassasiyet
JavaScript sayıları IEEE 754 çift duyarlıklıdır. PHP int değerleri platformun yerel türündedir (her modern derlemede 64 bit). Dönüştürme, ±2^53'e kadar olan tamsayıları tam olarak korur; daha büyük PHP int değerleri number olur ve 16 ondalık basamaktan sonra hassasiyetini kaybeder. Bundan daha büyük tamsayılarda tam aritmetik gerekiyorsa JS içinde BigInt kullanın ve sonucu dizge olarak dışarı aktarın.
Dizgeler
PHP dizgeleri bayt dizileridir; JS dizgeleri UTF-16 kod birimi dizileridir. Motor, PHP baytlarını UTF-8 olarak yorumlayıp dahili olarak UTF-16'ya yeniden kodlayarak aralarında köprü kurar. Geçerli UTF-8 girdilerinde bu işlem kayıpsızdır. Geçerli UTF-8 olmayan baytlar, U+FFFD ile değiştirilmek yerine değiştirilmeden aktarılır.
String.length, indeksli erişim (s[0]) ve dilimleme işlemlerinin tümü ECMAScript belirtimine göre UTF-16 kod birimlerini sayar; kod noktalarını veya baytları değil. Bu nedenle '🍕' gibi astral karakterler içeren dizgelerde .length === 2 bulunur (U+1F355'in iki vekil yarısı).
Gidiş dönüş kararlılığı
Düz veriler gidiş dönüşte korunur: setGlobal() üzerinden girip eval() veya call() üzerinden dönen, skaler değerlerden, listelerden ve ilişkisel dizilerden oluşan bir PHP değeri aynı yapıyı üretir; tam sayı değerindeki kayan noktalı sayılar int olarak geri döner (1.0, 1 döndürür).
Yukarıdaki tablolarda null, undefined veya [] ile eşlenen diğer hiçbir değer gidiş dönüşte korunmaz.