Sdílené objekty
Předávání objektu PHP do JavaScript odkazem — čtení jeho vlastností, volání metod a sledování změn v PHP — zatím není podporováno. Je to evidováno v issue #18. Tato stránka popisuje současné chování a funkční alternativní postupy.
Současné chování
setGlobal() převádí svou hodnotu podle pravidel v části Převod hodnot. Objekt PHP, který nelze volat, nemá žádný převod, takže globální proměnná má hodnotu 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')
Totéž platí pro stdClass, entity a modely, kontejnery služeb, generátory a zdroje. Výjimkou jsou dva typy volatelných objektů:
- Objekt s
__invoke()se změní na funkci JS, která jej zavolá. - Volatelné pole, například
[$counter, 'increment'], se změní na funkci JS, která zavolá danou metodu.
Pro zpřístupnění objektů neexistuje žádná třída PhpBridge ani jiný obal; src/Interop/ obsahuje pouze převaděč hodnot.
Zpřístupnění metod pomocí uzávěrů
Uzávěr může zachytit objekt, takže JS volá funkci a metoda se spustí nad původní instancí 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
Volatelné pole dosáhne stejného výsledku bez uzávěru:
$engine->setGlobal('increment', [$counter, 'increment']);
Seskupení do pole
Asociativní pole se změní na objekt JS a uzávěry uvnitř na funkce. Tím získá JS objekt ve tvaru API, jehož metody pracují s instancí 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 vidí pouze to, co vložíte do pole, takže soukromý stav, například $secret, zůstává v PHP.
Datová pole jsou kopie pořízené při spuštění setGlobal(). V příkladu je user.name řetězec v JS; přiřazením se změní jeho kopie JS, nikoli $user->name. Všechny zápisy provádějte prostřednictvím uzávěru.
Předání dat ven a výsledků zpět
U objektů tvořených daty je při předání převeďte na pole a při návratu přečtěte výsledek:
$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) nebo metoda toArray() vám poskytne pole odpovídající objektu. Poté použijte vrácené pole na objekt, entitu nebo model v PHP.
Omezení
- Výjimky vyvolané uvnitř těchto uzávěrů aktuálně nemůže zachytit JS
try/catch; dostanou se k volajícímueval()(issue #20). Viz Hostitelské funkce. - Uzávěr registrovaný pomocí
setGlobal()udržuje zachycené objekty naživu, dokud engine drží globální proměnnou.