Reikšmių konvertavimas
Kiekvienas kvietimas, peržengiantis PHP↔JS ribą, — setGlobal, call arba iš JS iškviečiama pagrindinio kompiuterio funkcija, — pereina per konverterį:
- PHP → JS, kai pagrindinio kompiuterio reikšmės patenka į variklį (
setGlobal(),call()argumentai, pagrindinio kompiuterio funkcijų grąžinamos reikšmės). - JS → PHP, kai JS reikšmės perduodamos atgal. Yra du keliai su šiek tiek skirtingomis taisyklėmis:
eval()ircall()rezultatai bei argumentai, kuriuos JS perduoda pagrindinio kompiuterio funkcijai.
Konvertuojant sukuriamos kopijos. Primityviosios reikšmės susiejamos su primityviosiomis, masyvai ir objektai nukopijuojami į naujas struktūras, o PHP kviečiamieji objektai apgaubiami kaip JS funkcijos. Niekuo nebendrinama pagal nuorodą, išskyrus pačius kviečiamuosius objektus.
PHP → JS
| PHP reikšmė | JS rezultatas |
|---|---|
null |
null |
true / false |
true / false |
int |
number (IEEE 754 double; sveikieji skaičiai, didesni nei 2^53, praranda tikslumą) |
float |
number (NaN, ±Infinity, ±0 išsaugomi) |
string |
string (UTF-8 PHP baitai interpretuojami kaip UTF-16 kodo vienetai), net jei pavadinimas nurodo PHP funkciją |
sąrašas array (raktai 0, 1, 2, … eilės tvarka) |
naujas Array, elementai konvertuojami rekursyviai |
bet kuris kitas array |
naujas paprastas Object, reikšmės konvertuojamos rekursyviai |
Closure, iškviečiamasis objektas, kviečiamasis masyvas, pavyzdžiui, [$object, 'method'] |
function, iškviečiantis kviečiamąjį PHP |
bet kuris kitas objektas, Generator, išteklius |
undefined |
Masyvai su mišriais raktais (PHP [0 => 'a', 'name' => 'b']) tampa paprastais objektais, nes JS masyvai privalo turėti ištisinę sveikųjų skaičių indeksų seką.
$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
Kadangi masyvai kopijuojami, JS pakeitimai lieka JS pusėje:
$list = [1, 2, 3];
$engine->setGlobal('list', $list);
$engine->eval('list.push(4)');
count($list); // 3
$engine->eval('list.length'); // 4
PHP nekviečiami objektai nekonvertuojami; jie perduodami kaip undefined (18 klaida). Pirmiausia konvertuokite juos į masyvus, pavyzdžiui, naudodami get_object_vars(), arba atskleiskite jų metodus kaip uždarinius. Žr. Bendrinami objektai.
JS → PHP: eval() ir call() rezultatai
| JS reikšmė | PHP rezultatas |
|---|---|
undefined, null |
null |
boolean |
bool |
number (sveikasis skaičius, telpantis int intervale) |
int (-0 tampa 0) |
NaN, Infinity, -Infinity |
NAN, INF, -INF |
number (kitas) |
float |
string |
string (UTF-8) |
bigint, symbol |
null |
function |
null |
Array |
sąrašas array, elementai konvertuojami rekursyviai |
TypedArray |
skaičių sąrašas array |
bet kuris kitas objektas (paprasti objektai, Error, Date, Map, Set, Promise, ArrayBuffer, …) |
asociatyvusis array, sudarytas iš jo paties duomenų savybių; prieigos savybės ir funkcijų reikšmes turinčios savybės praleidžiamos |
Paskutinės eilutės atveju objektai, kurių būsena saugoma vidiniuose lizduose, konvertuojami į tuščią masyvą: new Date(0), new Map([["a", 1]]) ir Promise.resolve(5) visi grąžina []. Error grąžina savo message ir stack. Objektas su nuoroda į save savo vidines nuorodas konvertuoja į null.
$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)'); // []
Jei kurią nors iš šių reikšmių reikia naudoti PHP, konvertuokite ją JS viduje:
$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: pagrindinio kompiuterio funkcijų argumentai
Argumentams, kuriuos JS perduoda PHP pagrindinio kompiuterio funkcijai, taikomos tos pačios primityviųjų reikšmių, masyvų ir paprastų objektų taisyklės su šiais skirtumais:
| JS reikšmė | PHP argumentas |
|---|---|
TypedArray, ArrayBuffer, DataView |
paties variklio JsValue objektas, nekonvertuotas |
| objektas | asociatyvusis array, apimantis visas jo savybes, įskaitant prieigos savybes (kurių gavimo funkcijos vykdomos) ir funkcijų reikšmes turinčias savybes |
| rodyklinė funkcija | array (paprastai tuščias) |
function, deklaruotas naudojant raktažodį function, arba bet kuris objektas, nurodantis į save |
nekonvertuojamas: kopijavimas niekada nesibaigia, o PHP pritrūksta atminties (issue #21) |
Kol kas negalima gauti JS atgalinio iškvietimo pagrindinio kompiuterio funkcijoje. Per šią ribą perduokite duomenis, o ne funkcijas.
Skaičiai ir tikslumas
JavaScript skaičiai yra IEEE 754 double. PHP sveikieji skaičiai priklauso nuo platformos (visose šiuolaikinėse versijose – 64 bitų). Konvertuojant tiksliai išsaugomi sveikieji skaičiai iki ±2^53; didesni PHP sveikieji skaičiai tampa number, todėl praranda tikslumą po 16 dešimtainių skaitmenų. Jei reikia tiksliai atlikti aritmetinius veiksmus su didesniais sveikaisiais skaičiais, naudokite BigInt JS viduje ir perduokite rezultatą kaip eilutę.
Eilutės
PHP eilutės yra baitų masyvai, o JS eilutės – UTF-16 kodo vienetų sekos. Variklis jas susieja, interpretuodamas PHP baitus kaip UTF-8 ir viduje perkoduodamas į UTF-16. Jei įvestis yra tinkamas UTF-8, duomenys neprarandami. Netinkami UTF-8 baitai perduodami nepakeisti, jų nepakeičiant U+FFFD.
String.length, indeksavimas (s[0]) ir dalies iškirpimas skaičiuoja UTF-16 kodo vienetus pagal ECMAScript specifikaciją — ne kodo taškus ir ne baitus. Todėl eilutėse su astraliniais simboliais, pavyzdžiui, '🍕', yra .length === 2 (dvi pakaitinės U+1F355 dalys).
Grįžtamojo konvertavimo stabilumas
Paprasti duomenys po konvertavimo pirmyn ir atgal išlieka: PHP reikšmė, sudaryta iš skaliarų, sąrašų ir asociatyviųjų masyvų, perduota per setGlobal() ir grąžinta per eval() arba call(), išlaiko tą pačią struktūrą. Išimtis – sveikųjų skaičių reikšmes turinčios slankiojo kablelio reikšmės grįžta kaip int (1.0 grąžina 1).
Visa kita pirmiau pateiktose lentelėse, kas susiejama su null, undefined arba [], po konvertavimo pirmyn ir atgal neišlieka.