
# 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](https://github.com/inline0/phasis/issues/18). Š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](https://phasis.inline0.dev/lv/docs/interop/values). 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](https://github.com/inline0/phasis/issues/20)). Skatiet sadaļu [Resursdatora funkcijas](https://phasis.inline0.dev/lv/docs/interop/host-functions#throwing-back-into-js).
- 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.
