
# Obiecte partajate

Transmiterea unui obiect PHP către JavaScript prin referință — citirea proprietăților, apelarea metodelor și observarea modificărilor în PHP — **nu este încă acceptată**. Problema este urmărită în [problema nr. 18](https://github.com/inline0/phasis/issues/18). Această pagină descrie comportamentul actual și tiparele alternative care funcționează.

## Comportamentul actual

`setGlobal()` își convertește valoarea conform regulilor din [Conversia valorilor](https://phasis.inline0.dev/ro/docs/interop/values). Un obiect PHP care nu este apelabil nu are o conversie, astfel că valoarea globală este `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')
```

Același lucru se aplică pentru `stdClass`, entități și modele, containere de servicii, generatoare și resurse. Există două excepții: obiectele apelabile:

- Un obiect cu `__invoke()` devine o funcție JS care îl apelează.
- Un tablou apelabil, precum `[$counter, 'increment']`, devine o funcție JS care apelează acea metodă.

Nu există `PhpBridge` sau altă clasă wrapper pentru expunerea obiectelor; `src/Interop/` conține doar convertorul de valori.

## Expunerea metodelor ca funcții closure

O funcție closure poate captura obiectul, astfel că JS apelează o funcție, iar metoda rulează pe instanța PHP originală:

```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 tablou apelabil face același lucru fără o funcție closure:

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

## Gruparea într-un tablou

Un tablou asociativ devine un obiect JS, iar funcțiile closure din interior devin funcții. Astfel, JS primește un obiect API ale cărui metode operează asupra instanței 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
```

Doar elementele incluse în tablou sunt vizibile pentru JS, astfel că starea privată, precum `$secret`, rămâne în PHP.

Câmpurile de date sunt copii preluate când rulează `setGlobal()`. În exemplu, `user.name` este un șir în JS; atribuirea unei valori îi modifică copia JS, nu pe `$user->name`. Efectuați toate scrierile printr-o funcție closure.

## Transmiterea datelor și returnarea rezultatelor

Pentru obiecte structurate ca date, convertiți la intrare într-un tablou și citiți rezultatul la ieșire:

```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)` sau o metodă `toArray()` vă oferă tabloul unui obiect. Apoi aplicați tabloul returnat obiectului, entității sau modelului în PHP.

## Observații

- Excepțiile aruncate în interiorul acestor funcții anonime nu pot fi capturate momentan de JS `try` / `catch`; acestea ajung la apelantul lui `eval()` ([problema #20](https://github.com/inline0/phasis/issues/20)). Consultați [Funcții gazdă](https://phasis.inline0.dev/ro/docs/interop/host-functions#throwing-back-into-js).
- O funcție anonimă înregistrată cu `setGlobal()` menține în viață obiectele pe care le capturează cât timp motorul păstrează globalul.
