
# Oggetti condivisi

Passare un oggetto PHP per riferimento a JavaScript — leggerne le proprietà, invocarne i metodi e vederne le modifiche in PHP — **non è ancora supportato**. La questione è tracciata in [problema n. 18](https://github.com/inline0/phasis/issues/18). Questa pagina descrive cosa succede oggi e quali schemi usare al suo posto.

## Cosa succede oggi

`setGlobal()` converte il proprio valore secondo le regole descritte in [Conversione dei valori](https://phasis.inline0.dev/it/docs/interop/values). Un oggetto PHP non richiamabile non ha una conversione, quindi il valore globale è `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')
```

Lo stesso vale per `stdClass`, entità e modelli, contenitori di servizi, generatori e risorse. Fanno eccezione due tipi di oggetti richiamabili:

- Un oggetto con `__invoke()` diventa una funzione JS che lo invoca.
- Un array richiamabile come `[$counter, 'increment']` diventa una funzione JS che invoca quel metodo.

Non esiste una classe wrapper `PhpBridge` o di altro tipo per esporre gli oggetti; `src/Interop/` contiene solo il convertitore di valori.

## Esporre metodi tramite closure

Una closure può acquisire l'oggetto, così JS invoca una funzione e il metodo opera sull'istanza PHP originale:

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

Un array richiamabile fa lo stesso senza una closure:

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

## Raggrupparli in un array

Un array associativo diventa un oggetto JS e le closure al suo interno diventano funzioni. In questo modo JS ottiene un API con struttura a oggetto, i cui metodi operano sull'istanza 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
```

Solo ciò che inserisci nell'array è visibile a JS, quindi lo stato privato, come `$secret`, rimane in PHP.

I campi dati sono copie create quando viene eseguito `setGlobal()`. Nell'esempio, `user.name` è una stringa in JS; assegnarle un valore modifica la copia JS, non `$user->name`. Instrada ogni scrittura tramite una closure.

## Passare i dati e ricevere i risultati

Per gli oggetti che rappresentano dati, convertili in un array all'ingresso e leggi il risultato all'uscita:

```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)` o un metodo `toArray()` restituisce l'array dell'oggetto. Poi applica l'array restituito all'oggetto, all'entità o al modello in PHP.

## Avvertenze

- Le eccezioni lanciate all'interno di queste closure al momento non possono essere intercettate da JS `try` / `catch`; raggiungono il chiamante di `eval()` ([problema n. 20](https://github.com/inline0/phasis/issues/20)). Vedi [Funzioni host](https://phasis.inline0.dev/it/docs/interop/host-functions#throwing-back-into-js).
- Una closure registrata con `setGlobal()` mantiene in vita gli oggetti che acquisisce finché il motore conserva il globale.
