Pereiti prie turinio

Bendrinami objektai

Perduoti PHP objektą į JavaScript pagal nuorodą — skaityti jo savybes, iškviesti metodus ir matyti pakeitimus PHP — kol kas nepalaikoma. Šis apribojimas stebimas: issue #18. Šiame puslapyje aprašoma, kas vyksta dabar, ir kokie būdai veikia vietoj to.

Kas vyksta dabar

setGlobal() konvertuoja reikšmę pagal Reikšmių konvertavimo taisykles. Nekviečiamas PHP objektas konvertavimo būdo neturi, todėl globalioji reikšmė yra undefined:

PHP
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')

Tas pats taikoma stdClass, esybėms ir modeliams, paslaugų konteineriams, generatoriams bei ištekliams. Išimtys yra kviečiamieji objektai:

  • Objektas su __invoke() tampa JS funkcija, kuri jį iškviečia.
  • Kviečiamasis masyvas, pavyzdžiui, [$counter, 'increment'], tampa JS funkcija, kuri iškviečia tą metodą.

Objektams atskleisti nėra nei PhpBridge, nei kitos apvalkalinės klasės; src/Interop/ yra tik reikšmių konverteris.

Atskleiskite metodus kaip uždarinius

Uždarinyje galima užfiksuoti objektą, todėl JS iškviečia funkciją, o metodas vykdomas pradiniame PHP egzemplioriuje:

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

Kviečiamasis masyvas tą patį atlieka be uždarinio:

PHP
$engine->setGlobal('increment', [$counter, 'increment']);

Sugrupuokite juos į masyvą

Asociatyvusis masyvas tampa JS objektu, o jame esantys uždariniai – funkcijomis. Taip JS gauna objektą primenantį API, kurio metodai veikia su PHP egzemplioriumi:

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 mato tik tai, ką įdedate į masyvą, todėl privati būsena, pavyzdžiui, $secret, lieka PHP pusėje.

Duomenų laukai yra kopijos, sukurtos vykdant setGlobal(). Pavyzdyje user.name yra eilutė JS; jai priskyrus reikšmę, pakeičiama JS kopija, o ne $user->name. Kiekvieną įrašymą atlikite per uždarinį.

Perduokite duomenis ir grąžinkite rezultatus

Duomenų struktūros objektus konvertuokite į masyvą perduodami, o grąžintą rezultatą nuskaitykite atgal:

PHP
$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) arba toArray() metodas pateikia objekto masyvą. Tada pritaikykite grąžintą masyvą savo objektui, esybei arba modeliui PHP aplinkoje.

Apribojimai

  • Šių uždarinių viduje iškeltų išimčių šiuo metu negalima pagauti naudojant JS try / catch; jos pasiekia eval() iškvietėją (issue #20). Žr. Pagrindinio kompiuterio funkcijos.
  • Užregistravus uždarinį su setGlobal(), jo užfiksuoti objektai išlieka gyvi, kol variklis laiko globaliąją reikšmę.