Zdieľané objekty
Odovzdanie objektu PHP do JavaScript prostredníctvom referencie — čítanie jeho vlastností, volanie jeho metód a sledovanie zmien v PHP — zatiaľ nie je podporované. Eviduje sa to v probléme č. 18. Táto stránka opisuje, čo sa deje dnes a ktoré postupy možno použiť namiesto toho.
Čo sa deje dnes
setGlobal() konvertuje svoju hodnotu podľa pravidiel v Konverzia hodnôt. Objekt PHP, ktorý nemožno volať, sa nekonvertuje, takže globálna premenná je 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')
To isté platí pre stdClass, entity a modely, servisné kontajnery, generátory a zdroje. Výnimkou sú volateľné objekty:
- Objekt s
__invoke()sa zmení na funkciu JS, ktorá ho zavolá. - Volateľné pole, napríklad
[$counter, 'increment'], sa zmení na funkciu JS, ktorá zavolá danú metódu.
Neexistuje PhpBridge ani iná obalová trieda na sprístupnenie objektov; src/Interop/ obsahuje iba konvertor hodnôt.
Sprístupnenie metód ako uzáverov
Uzáver môže zachytiť objekt, takže JS zavolá funkciu a metóda sa vykoná nad pôvodnou inštanciou PHP:
$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
Volateľné pole dosahuje to isté bez uzáveru:
$engine->setGlobal('increment', [$counter, 'increment']);
Zoskupenie do poľa
Asociatívne pole sa zmení na objekt JS a uzávery v ňom sa zmenia na funkcie. Takto získa JS objekt API, ktorého metódy pracujú s inštanciou 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
Pre JS sú viditeľné iba položky, ktoré vložíte do poľa, takže súkromný stav, napríklad $secret, zostane v PHP.
Dátové polia sú kópie vytvorené pri spustení setGlobal(). V príklade je user.name reťazec v JS; priradenie zmení kópiu JS, nie $user->name. Každý zápis vykonávajte prostredníctvom uzáveru.
Odovzdanie dát a získanie výsledkov
Pri objektoch s dátovou štruktúrou ich na vstupe preveďte na pole a na výstupe načítajte výsledok:
$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) alebo metóda toArray() vám poskytne pole objektu. Potom v PHP použite vrátené pole na aktualizáciu objektu, entity alebo modelu.
Upozornenia
- Výnimky vyvolané v týchto uzáveroch zatiaľ nemožno zachytiť v JS
try/catch; dostanú sa k volajúcemueval()(problém č. 20). Pozrite si Hostiteľské funkcie. - Uzáver zaregistrovaný pomocou
setGlobal()udržiava zachytené objekty nažive, kým engine uchováva globálnu premennú.