Pereiti prie turinio

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() ir call() 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ą.

PHP
$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:

PHP
$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.

PHP
$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:

PHP
$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.