Pāriet uz saturu

Koplietojami objekti

PHP objekta nodošana JavaScript pēc atsauces — tā īpašību lasīšana, metožu izsaukšana un izmaiņu redzēšana PHP — vēl netiek atbalstīta. Tas ir reģistrēts kā 18. problēma. Šajā lapā aprakstīts, kas notiek pašlaik un kādi paņēmieni darbojas tā vietā.

Kas notiek pašlaik

setGlobal() pārveido vērtību saskaņā ar noteikumiem, kas aprakstīti sadaļā Vērtību pārveide. PHP objektam, kas nav izsaucams, nav atbilstošas pārveides, tāpēc globālā vērtība ir 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 attiecas uz stdClass, entītijām un modeļiem, pakalpojumu konteineriem, ģeneratoriem un resursiem. Izņēmums ir divu veidu izsaucami objekti:

  • Objekts ar __invoke() kļūst par JS funkciju, kas to izsauc.
  • Izsaucams masīvs, piemēram, [$counter, 'increment'], kļūst par JS funkciju, kas izsauc attiecīgo metodi.

Objektu atklāšanai nav ne PhpBridge, ne citas iesaiņotāja klases; src/Interop/ ietver tikai vērtību pārveidotāju.

Atklājiet metodes kā slēgtās funkcijas

Slēgtā funkcija var saglabāt objektu, tāpēc JS izsauc funkciju, un metode darbojas sākotnējā PHP 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

Izsaucams masīvs dara to pašu bez slēgtās funkcijas:

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

Grupējiet tās masīvā

Asociatīvais masīvs kļūst par JS objektu, un tajā iekļautās slēgtās funkcijas kļūst par funkcijām. Tādējādi JS iegūst objektam līdzīgu API, kura metodes darbojas ar PHP instanci:

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 ir redzams tikai tas, ko iekļaujat masīvā, tāpēc privāts stāvoklis, piemēram, $secret, paliek PHP.

Datu lauki ir kopijas, kas iegūtas brīdī, kad darbojas setGlobal(). Piemērā user.name ir virkne JS; piešķirot tai vērtību, tiek mainīta JS kopija, nevis $user->name. Visas ierakstīšanas darbības veiciet, izmantojot slēgto funkciju.

Nododiet datus un saņemiet rezultātus

Datu objektiem pārveidojiet tos par masīvu, nododot iekšā, un nolasiet rezultātu, saņemot to atpakaļ:

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) vai toArray() metode nodrošina objekta masīvu. Pēc tam lietojiet atgriezto masīvu savam objektam, entītijai vai modelim PHP.

Ierobežojumi

  • JS šajās slēgtajās funkcijās pašlaik nevar uztvert try catch izņēmumus; tie nonāk līdz eval() izsaucējam (20. problēma). Skatiet sadaļu Resursdatora funkcijas.
  • Slēgtā funkcija, kas reģistrēta ar setGlobal(), uztur savus objektus dzīvus tik ilgi, kamēr dzinējs saglabā globālo vērtību.