
# Obiekty współdzielone

Przekazywanie obiektu PHP do JavaScript przez referencję — odczytywanie jego właściwości, wywoływanie metod i obserwowanie zmian w PHP — **nie jest jeszcze obsługiwane**. Śledzimy to w [zgłoszeniu #18](https://github.com/inline0/phasis/issues/18). Ta strona opisuje obecne działanie i wzorce, których można użyć zamiast tego.

## Obecne działanie

`setGlobal()` konwertuje wartość zgodnie z regułami opisanymi w [Konwersja wartości](https://phasis.inline0.dev/pl/docs/interop/values). Obiekt PHP, który nie jest funkcją wywoływalną, nie ma konwersji, więc zmienna globalna ma wartość `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')
```

To samo dotyczy `stdClass`, encji i modeli, kontenerów usług, generatorów i zasobów. Wyjątkiem są dwa rodzaje obiektów wywoływalnych:

- Obiekt z `__invoke()` staje się funkcją JS, która go wywołuje.
- Tablica wywoływalna, taka jak `[$counter, 'increment']`, staje się funkcją JS wywołującą tę metodę.

Nie ma klasy `PhpBridge` ani innej klasy opakowującej do udostępniania obiektów; `src/Interop/` zawiera wyłącznie konwerter wartości.

## Udostępnianie metod jako domknięć

Domknięcie może przechwycić obiekt, więc JS wywołuje funkcję, a metoda działa na pierwotnej instancji PHP:

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

Tablica wywoływalna działa tak samo, bez domknięcia:

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

## Grupowanie w tablicy

Tablica asocjacyjna staje się obiektem JS, a zawarte w niej domknięcia — funkcjami. Dzięki temu JS otrzymuje obiektowy API, którego metody działają na instancji 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
```

Dla JS widoczne są tylko elementy umieszczone w tablicy, więc prywatny stan, taki jak `$secret`, pozostaje w PHP.

Pola danych są kopiowane w chwili uruchomienia `setGlobal()`. W przykładzie `user.name` jest ciągiem w JS; przypisanie do niego zmienia kopię JS, a nie `$user->name`. Każdą zmianę wykonuj przez domknięcie.

## Przekazywanie danych na zewnątrz i wyników z powrotem

W przypadku obiektów reprezentujących dane zamień je na tablicę przy przekazywaniu do silnika i odczytaj wynik przy odbieraniu:

```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)` lub metoda `toArray()` zwraca tablicę dla obiektu. Następnie przekaż zwróconą tablicę do obiektu, encji lub modelu w PHP.

## Ograniczenia

- Wyjątki zgłoszone wewnątrz tych funkcji domknięcia nie mogą być obecnie przechwycone przez JS `try` / `catch`; trafiają do wywołującego `eval()` ([issue #20](https://github.com/inline0/phasis/issues/20)). Zobacz [Funkcje hosta](https://phasis.inline0.dev/pl/docs/interop/host-functions#throwing-back-into-js).
- Funkcja domknięcia zarejestrowana przez `setGlobal()` utrzymuje przy życiu przechwycone obiekty tak długo, jak silnik przechowuje zmienną globalną.
