Jagatud objektid
PHP objekti viitena JavaScript-ile edastamine — selle atribuutide lugemine, meetodite kutsumine ja muudatuste nägemine PHP-s — pole veel toetatud. Seda jälgitakse probleemis #18. See leht kirjeldab praegust käitumist ja toimivaid mustreid.
Praegune käitumine
setGlobal() teisendab väärtuse Väärtuse teisendamise reeglite järgi. Kutsumatu PHP objekt ei teisendu, seega on globaalne väärtus 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')
Sama kehtib stdClass, olemite ja mudelite, teenusekonteinerite, generaatorite ning ressursside kohta. Erandiks on kaks väljakutsutavat objekti:
- Objektist, millel on
__invoke(), saab funktsioon JS, mis kutsub seda objekti. - Kutsutavast massiivist, näiteks
[$counter, 'increment'], saab funktsioon JS, mis kutsub seda meetodit.
Objektide avaldamiseks pole klassi PhpBridge ega ühtegi muud ümbrisklassi; src/Interop/ sisaldab ainult väärtusteisendajat.
Avaldage meetodid sulunditena
Sulund saab objekti endaga kaasa võtta, nii et JS kutsub funktsiooni ja meetod käivitatakse algse PHP eksemplari peal:
$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
Kutsutav massiiv teeb sama ilma sulundita:
$engine->setGlobal('increment', [$counter, 'increment']);
Rühmitage need massiivi
Assotsiatiivsest massiivist saab objekt JS ja selles olevatest sulunditest funktsioonid. Nii saab JS objektikujulise API, mille meetodid toimivad eksemplaril PHP:
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 näeb ainult massiivi lisatud väärtusi, seega jäävad privaatsed andmed nagu $secret PHP-i.
Andmeväljad kopeeritakse siis, kui setGlobal() käivitub. Näites on user.name string väärtuses JS; sellele väärtuse määramine muudab koopiat JS, mitte väärtust $user->name. Suunake kõik kirjutustoimingud sulundi kaudu.
Andmete edastamine ja tulemuste tagastamine
Andmekujuliste objektide korral teisenda need sisse tulles massiiviks ja loe tulemus välja minnes:
$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) või meetod toArray() annab objekti kohta massiivi. Seejärel rakenda tagastatud massiiv oma objektile, olemile või mudelile PHP-s.
Piirangud
- Nendes sulundites visatud erindeid ei saa praegu kinni püüda JS
try/catchabil; need jõuavad funktsioonieval()kutsujani (probleem #20). Vt Host functions. setGlobal()abil registreeritud sulund hoiab jäädavalt elus selles hõivatud objekte nii kaua, kui mootor hoiab globaalset objekti.