Deljeni objekti
Posredovanje objekta PHP v JavaScript po sklicu — branje njegovih lastnosti, klicanje metod in spremljanje sprememb v PHP — še ni podprto. Spremljajte težavo št. 18. Ta stran opisuje trenutno vedenje in vzorce, ki delujejo kot alternativa.
Trenutno vedenje
setGlobal() pretvori vrednost po pravilih v Pretvorba vrednosti. Objekt PHP, ki ni klicen, nima ustrezne pretvorbe, zato je globalna vrednost 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')
Enako velja za stdClass, entitete in modele, vsebnike storitev, generatorje ter vire. Izjemi sta dva klicna objekta:
- Objekt z
__invoke()postane funkcija JS, ki ga pokliče. - Klicna tabela, kot je
[$counter, 'increment'], postane funkcija JS, ki pokliče to metodo.
Za izpostavljanje objektov ni PhpBridge ali drugega ovijalnega razreda; src/Interop/ vsebuje samo pretvornik vrednosti.
Izpostavljanje metod kot zaprtih funkcij
Zaprta funkcija lahko zajame objekt, zato JS pokliče funkcijo, metoda pa se izvede na prvotnem primerku 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
Klicna tabela doseže enako brez zaprte funkcije:
$engine->setGlobal('increment', [$counter, 'increment']);
Združevanje v tabeli
Asociativna tabela postane objekt JS, zaprte funkcije v njej pa postanejo funkcije. Tako JS dobi objektu podobno vrednost API, katere metode delujejo na primerku 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
Za JS je vidno samo to, kar dodate v tabelo, zato zasebno stanje, kot je $secret, ostane v PHP.
Podatkovna polja so kopije, ustvarjene ob klicu setGlobal(). V tem primeru je user.name niz v JS; njegova sprememba vpliva na kopijo JS, ne pa na $user->name. Vsako pisanje izvedite prek zaprte funkcije.
Posredovanje podatkov navzven in rezultatov nazaj
Pri objektih, oblikovanih kot podatki, jih ob vhodu pretvorite v polje, rezultat pa ob izhodu preberite:
$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) ali metoda toArray() za objekt vrne polje. Nato vrnjeno polje uporabite za objekt, entiteto ali model v PHP.
Omejitve
- Izjem, sproženih znotraj teh zaprtij, trenutno ni mogoče ujeti z JS
try/catch; dosežejo klicateljaeval()(težava #20). Glejte Gostiteljske funkcije. - Zaprtje, registrirano z
setGlobal(), ohrani objekte, ki jih zajame, pri življenju, dokler mehanizem hrani globalno spremenljivko.