
# 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](https://github.com/inline0/phasis/issues/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](https://phasis.inline0.dev/lt/docs/interop/values) 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](https://github.com/inline0/phasis/issues/20)). Žr. [Pagrindinio kompiuterio funkcijos](https://phasis.inline0.dev/lt/docs/interop/host-functions#throwing-back-into-js).
- Užregistravus uždarinį su `setGlobal()`, jo užfiksuoti objektai išlieka gyvi, kol variklis laiko globaliąją reikšmę.
