
# Megosztott objektumok

Egy PHP objektum referenciaként történő átadása a JavaScript számára — a tulajdonságok olvasása, a metódusok hívása és a PHP-ban végzett módosítások észlelése — **egyelőre nem támogatott**. A fejlesztést a [18. számú issue](https://github.com/inline0/phasis/issues/18) követi. Ez az oldal bemutatja a jelenlegi működést és a helyette használható megoldásokat.

## Jelenlegi működés

A `setGlobal()` az értékét az [Értékkonverzió](https://phasis.inline0.dev/hu/docs/interop/values) szabályai szerint konvertálja. A nem hívható PHP objektumok nem konvertálhatók, ezért a globális változó értéke `undefined` lesz:

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

Ugyanez érvényes a `stdClass` elemekre, entitásokra és modellekre, szolgáltatástárolókra, generátorokra és erőforrásokra. Két kivétel van: a hívható objektumok:

- A `__invoke()` tulajdonsággal rendelkező objektumból JS függvény lesz, amely meghívja azt.
- Az olyan hívható tömbből, mint a `[$counter, 'increment']`, JS függvény lesz, amely meghívja az adott metódust.

Nincs `PhpBridge` vagy más burkolóosztály az objektumok közzétételéhez; a `src/Interop/` csak az értékkonvertert tartalmazza.

## Metódusok közzététele closure-ökként

A closure rögzítheti az objektumot, így a JS egy függvényt hív meg, a metódus pedig az eredeti PHP példányon fut le:

```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
```

A hívható tömb ugyanezt teszi closure nélkül:

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

## Csoportosítás tömbbe

Az asszociatív tömb JS objektummá válik, a benne lévő closure-ök pedig függvényekké. Így a JS egy objektumszerű API-t kap, amelynek metódusai az PHP példányon működnek:

```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
```

A JS csak azt látja, amit beletesz a tömbbe, ezért a privát állapot, például a `$secret`, a PHP környezetében marad.

Az adatmezők másolatként jönnek létre a `setGlobal()` futásakor. A példában a `user.name` karakterlánc a JS környezetében; ha értéket rendel hozzá, az JS másolat változik meg, nem a `$user->name`. Minden írási műveletet closure-ön keresztül végezzen.

## Adat átadása és eredmények visszaolvasása

Adatként ábrázolható objektumoknál alakítsa az adatot tömbbé az átadáskor, majd olvassa ki az eredményt visszatéréskor:

```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
```

A `get_object_vars($object)` vagy egy `toArray()` metódus adja vissza az objektum tömbös reprezentációját. Ezután alkalmazza a visszakapott tömböt a PHP környezetben lévő objektumára, entitására vagy modelljére.

## Tudnivalók

- Az ezekben a closure-ökben dobott kivételeket jelenleg nem tudja elkapni a JS `try` / `catch`; azok a `eval()` hívójához jutnak el ([20. számú issue](https://github.com/inline0/phasis/issues/20)). Lásd: [Gazdafüggvények](https://phasis.inline0.dev/hu/docs/interop/host-functions#throwing-back-into-js).
- A `setGlobal()` által regisztrált closure életben tartja a rögzített objektumokat, amíg a motor megőrzi a globális változót.
