
# Jagatud objektid

PHP objekti viitena JavaScript-ile edastamine — selle atribuutide lugemine, meetodite kutsumine ja muudatuste nägemine PHP-s — **pole veel toetatud**. Seda jälgitakse [probleemis #18](https://github.com/inline0/phasis/issues/18). See leht kirjeldab praegust käitumist ja toimivaid mustreid.

## Praegune käitumine

`setGlobal()` teisendab väärtuse [Väärtuse teisendamise](https://phasis.inline0.dev/et/docs/interop/values) reeglite järgi. Kutsumatu PHP objekt ei teisendu, seega on globaalne väärtus `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')
```

Sama kehtib `stdClass`, olemite ja mudelite, teenusekonteinerite, generaatorite ning ressursside kohta. Erandiks on kaks väljakutsutavat objekti:

- Objektist, millel on `__invoke()`, saab funktsioon JS, mis kutsub seda objekti.
- Kutsutavast massiivist, näiteks `[$counter, 'increment']`, saab funktsioon JS, mis kutsub seda meetodit.

Objektide avaldamiseks pole klassi `PhpBridge` ega ühtegi muud ümbrisklassi; `src/Interop/` sisaldab ainult väärtusteisendajat.

## Avaldage meetodid sulunditena

Sulund saab objekti endaga kaasa võtta, nii et JS kutsub funktsiooni ja meetod käivitatakse algse PHP eksemplari peal:

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

Kutsutav massiiv teeb sama ilma sulundita:

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

## Rühmitage need massiivi

Assotsiatiivsest massiivist saab objekt JS ja selles olevatest sulunditest funktsioonid. Nii saab JS objektikujulise API, mille meetodid toimivad eksemplaril PHP:

```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 näeb ainult massiivi lisatud väärtusi, seega jäävad privaatsed andmed nagu `$secret` PHP-i.

Andmeväljad kopeeritakse siis, kui `setGlobal()` käivitub. Näites on `user.name` string väärtuses JS; sellele väärtuse määramine muudab koopiat JS, mitte väärtust `$user->name`. Suunake kõik kirjutustoimingud sulundi kaudu.

## Andmete edastamine ja tulemuste tagastamine

Andmekujuliste objektide korral teisenda need sisse tulles massiiviks ja loe tulemus välja minnes:

```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)` või meetod `toArray()` annab objekti kohta massiivi. Seejärel rakenda tagastatud massiiv oma objektile, olemile või mudelile PHP-s.

## Piirangud

- Nendes sulundites visatud erindeid ei saa praegu kinni püüda JS `try` / `catch` abil; need jõuavad funktsiooni `eval()` kutsujani ([probleem #20](https://github.com/inline0/phasis/issues/20)). Vt [Host functions](https://phasis.inline0.dev/et/docs/interop/host-functions#throwing-back-into-js).
- `setGlobal()` abil registreeritud sulund hoiab jäädavalt elus selles hõivatud objekte nii kaua, kui mootor hoiab globaalset objekti.
