Bendrinami objektai
Perduoti PHP objektą į JavaScript pagal nuorodą — skaityti jo savybes, iškviesti metodus ir matyti pakeitimus PHP — kol kas nepalaikoma. Šis apribojimas stebimas: issue #18. Šiame puslapyje aprašoma, kas vyksta dabar, ir kokie būdai veikia vietoj to.
Kas vyksta dabar
setGlobal() konvertuoja reikšmę pagal Reikšmių konvertavimo taisykles. Nekviečiamas PHP objektas konvertavimo būdo neturi, todėl globalioji reikšmė yra undefined:
class Counter {
public int $value = 0;
public function increment(): void { $this->value++; }
}
$counter = new Counter();
$engine->setGlobal('counter', $counter);
$engine->eval('typeof counter');
// "undefined"
$engine->eval('counter.increment()');
// throws Phasis\Exceptions\TypeError:
// Cannot read properties of undefined (reading 'increment')
Tas pats taikoma stdClass, esybėms ir modeliams, paslaugų konteineriams, generatoriams bei ištekliams. Išimtys yra kviečiamieji objektai:
- Objektas su
__invoke()tampa JS funkcija, kuri jį iškviečia. - Kviečiamasis masyvas, pavyzdžiui,
[$counter, 'increment'], tampa JS funkcija, kuri iškviečia tą metodą.
Objektams atskleisti nėra nei PhpBridge, nei kitos apvalkalinės klasės; src/Interop/ yra tik reikšmių konverteris.
Atskleiskite metodus kaip uždarinius
Uždarinyje galima užfiksuoti objektą, todėl JS iškviečia funkciją, o metodas vykdomas pradiniame PHP egzemplioriuje:
$counter = new Counter();
$engine->setGlobal('increment', fn () => $counter->increment());
$engine->setGlobal('count', fn () => $counter->value);
$engine->eval('increment(); increment(); count()');
// 2
echo $counter->value;
// 2
Kviečiamasis masyvas tą patį atlieka be uždarinio:
$engine->setGlobal('increment', [$counter, 'increment']);
Sugrupuokite juos į masyvą
Asociatyvusis masyvas tampa JS objektu, o jame esantys uždariniai – funkcijomis. Taip JS gauna objektą primenantį API, kurio metodai veikia su PHP egzemplioriumi:
class User {
public function __construct(
public string $name,
public int $age,
private string $secret,
) {}
public function greet(): string {
return "Hi, I'm $this->name";
}
}
$user = new User('Ada', 36, 'topsecret');
$engine->setGlobal('user', [
'name' => $user->name,
'greet' => fn () => $user->greet(),
'setAge' => function (int $age) use ($user): void { $user->age = $age; },
]);
$engine->eval('user.greet()');
// "Hi, I'm Ada"
$engine->eval('user.setAge(37)');
echo $user->age;
// 37
JS mato tik tai, ką įdedate į masyvą, todėl privati būsena, pavyzdžiui, $secret, lieka PHP pusėje.
Duomenų laukai yra kopijos, sukurtos vykdant setGlobal(). Pavyzdyje user.name yra eilutė JS; jai priskyrus reikšmę, pakeičiama JS kopija, o ne $user->name. Kiekvieną įrašymą atlikite per uždarinį.
Perduokite duomenis ir grąžinkite rezultatus
Duomenų struktūros objektus konvertuokite į masyvą perduodami, o grąžintą rezultatą nuskaitykite atgal:
$post = ['title' => 'Draft', 'tags' => ['php']];
$engine->setGlobal('post', $post);
$engine->eval('function edit(p) { p.title = "Edited from JS"; return p; }');
$post = $engine->call('edit', $post);
echo $post['title'];
// Edited from JS
get_object_vars($object) arba toArray() metodas pateikia objekto masyvą. Tada pritaikykite grąžintą masyvą savo objektui, esybei arba modeliui PHP aplinkoje.
Apribojimai
- Šių uždarinių viduje iškeltų išimčių šiuo metu negalima pagauti naudojant JS
try/catch; jos pasiekiaeval()iškvietėją (issue #20). Žr. Pagrindinio kompiuterio funkcijos. - Užregistravus uždarinį su
setGlobal(), jo užfiksuoti objektai išlieka gyvi, kol variklis laiko globaliąją reikšmę.