Jaetut oliot
PHP-olion välittäminen JavaScript:lle viitteenä — sen ominaisuuksien lukeminen, metodien kutsuminen ja muutosten näkeminen kohteessa PHP — ei ole vielä tuettua. Asiaa seurataan kohteessa issue #18. Tällä sivulla kuvataan, mitä nyt tapahtuu ja mitkä toimintatavat toimivat sen sijaan.
Mitä tällä hetkellä tapahtuu
setGlobal() muuntaa arvonsa arvojen muunnos-sivun sääntöjen mukaan. PHP-oliolle, joka ei ole kutsuttava, ei ole muunnosta, joten globaali saa arvon 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 koskee stdClass-olioita, entiteettejä ja malleja, palvelusäiliöitä, generaattoreita ja resursseja. Poikkeuksia ovat kaksi kutsuttavaa oliotyyppiä:
- Olio, jolla on
__invoke(), muuttuu JS-funktioksi, joka kutsuu sitä. - Kutsuttava taulukko, kuten
[$counter, 'increment'], muuttuu JS-funktioksi, joka kutsuu kyseistä metodia.
Olioiden tarjoamiseen ei ole PhpBridge-luokkaa tai muuta kääreluokkaa; src/Interop/ sisältää vain arvomuuntimen.
Metodien tarjoaminen sulkeumina
Sulkeuma voi pitää olion sisällään, jolloin JS kutsuu funktiota ja metodi suoritetaan alkuperäisessä PHP-instanssissa:
$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
Kutsuttavalla taulukolla saadaan sama aikaan ilman sulkeumaa:
$engine->setGlobal('increment', [$counter, 'increment']);
Ryhmittele ne taulukkoon
Assosiatiivinen taulukko muuttuu JS-olioksi, ja sen sisällä olevista sulkeumista tulee funktioita. Näin JS saa olion muotoisen API-olion, jonka metodit toimivat PHP-instanssissa:
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
Vain taulukkoon lisäämäsi sisältö näkyy kohteessa JS, joten yksityinen tila, kuten $secret, pysyy kohteessa PHP.
Tietokentät ovat kopioita, jotka otetaan, kun setGlobal() suoritetaan. Esimerkissä user.name on merkkijono kohteessa JS; sen asettaminen muuttaa JS-kopiota, ei arvoa $user->name. Ohjaa kaikki kirjoitukset sulkeuman kautta.
Vie tiedot ulos ja tulokset takaisin
Tietomaisille olioille voit muuntaa ne taulukoksi sisään mennessä ja lukea tuloksen ulos tullessa:
$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) tai toArray()-metodi antaa olion taulukkomuodossa. Käytä sitten palautettua taulukkoa olioon, entiteettiin tai malliin kohteessa PHP.
Huomioitavaa
- Näissä sulkeumissa heitettyjä poikkeuksia ei tällä hetkellä voi siepata JS-kohteen
try- taicatch-käsittelijöillä; ne päätyvät kohteeneval()kutsujalle (issue #20). Katso Isäntäfunktiot. setGlobal()-määrityksellä rekisteröity sulkeuma pitää sisälläänsä kaappaamansa oliot niin kauan kuin moottori säilyttää globaalin.