
# Jaetut oliot

PHP-olion välittäminen JavaScript:lle viitteenä — sen ominaisuuksien lukeminen, metodien kutsuminen ja muutosten näkeminen kohteessa PHP — **ei ole vielä tuettua**. Asiaa seurataan kohteessa [issue #18](https://github.com/inline0/phasis/issues/18). Tällä sivulla kuvataan, mitä nyt tapahtuu ja mitkä toimintatavat toimivat sen sijaan.

## Mitä tällä hetkellä tapahtuu

`setGlobal()` muuntaa arvonsa [arvojen muunnos](https://phasis.inline0.dev/fi/docs/interop/values)-sivun sääntöjen mukaan. PHP-oliolle, joka ei ole kutsuttava, ei ole muunnosta, joten globaali saa arvon `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 koskee `stdClass`-olioita, entiteettejä ja malleja, palvelusäiliöitä, generaattoreita ja resursseja. Poikkeuksia ovat kaksi kutsuttavaa oliotyyppiä:

- Olio, jolla on `__invoke()`, muuttuu JS-funktioksi, joka kutsuu sitä.
- Kutsuttava taulukko, kuten `[$counter, 'increment']`, muuttuu JS-funktioksi, joka kutsuu kyseistä metodia.

Olioiden tarjoamiseen ei ole `PhpBridge`-luokkaa tai muuta kääreluokkaa; `src/Interop/` sisältää vain arvomuuntimen.

## Metodien tarjoaminen sulkeumina

Sulkeuma voi pitää olion sisällään, jolloin JS kutsuu funktiota ja metodi suoritetaan alkuperäisessä PHP-instanssissa:

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

Kutsuttavalla taulukolla saadaan sama aikaan ilman sulkeumaa:

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

## Ryhmittele ne taulukkoon

Assosiatiivinen taulukko muuttuu JS-olioksi, ja sen sisällä olevista sulkeumista tulee funktioita. Näin JS saa olion muotoisen API-olion, jonka metodit toimivat PHP-instanssissa:

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

Vain taulukkoon lisäämäsi sisältö näkyy kohteessa JS, joten yksityinen tila, kuten `$secret`, pysyy kohteessa PHP.

Tietokentät ovat kopioita, jotka otetaan, kun `setGlobal()` suoritetaan. Esimerkissä `user.name` on merkkijono kohteessa JS; sen asettaminen muuttaa JS-kopiota, ei arvoa `$user->name`. Ohjaa kaikki kirjoitukset sulkeuman kautta.

## Vie tiedot ulos ja tulokset takaisin

Tietomaisille olioille voit muuntaa ne taulukoksi sisään mennessä ja lukea tuloksen ulos tullessa:

```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)` tai `toArray()`-metodi antaa olion taulukkomuodossa. Käytä sitten palautettua taulukkoa olioon, entiteettiin tai malliin kohteessa PHP.

## Huomioitavaa

- Näissä sulkeumissa heitettyjä poikkeuksia ei tällä hetkellä voi siepata JS-kohteen `try`- tai `catch`-käsittelijöillä; ne päätyvät kohteen `eval()` kutsujalle ([issue #20](https://github.com/inline0/phasis/issues/20)). Katso [Isäntäfunktiot](https://phasis.inline0.dev/fi/docs/interop/host-functions#throwing-back-into-js).
- `setGlobal()`-määrityksellä rekisteröity sulkeuma pitää sisälläänsä kaappaamansa oliot niin kauan kuin moottori säilyttää globaalin.
