
# Değer dönüştürme

PHP↔JS sınırını geçen her çağrı — `setGlobal`, `call`, JS üzerinden çağrılan bir ana makine işlevi — bir dönüştürücüden geçer:

- Ana makine değerleri motora aktarılırken **PHP → JS** (`setGlobal()`, `call()` bağımsız değişkenleri, ana makine işlevlerinin dönüş değerleri).
- JS değerleri geri dönerken **JS → PHP**. Biraz farklı kuralları olan iki yol vardır: `eval()` ve `call()` sonuçları ile JS'ın bir ana makine işlevine ilettiği bağımsız değişkenler.

Dönüştürme kopyalama yapar. İlkel değerler ilkel değerlere eşlenir, diziler ve nesneler yeni yapılara kopyalanır, PHP çağrılabilirleri ise JS işlevleri olarak sarılır. Çağrılabilirlerin kendileri dışında hiçbir şey başvuru yoluyla paylaşılmaz.

## PHP → JS

| PHP değeri | JS sonucu |
|---|---|
| `null` | `null` |
| `true` / `false` | `true` / `false` |
| `int` | `number` (IEEE 754 çift duyarlık; 2^53 üzerindeki tam sayılar hassasiyet kaybeder) |
| `float` | `number` (NaN, ±Infinity, ±0 korunur) |
| `string` | `string` (UTF-8 PHP baytları UTF-16 kod birimleri olarak yorumlanır); PHP işlevini adlandırsa bile |
| liste `array` (anahtarlar sırayla 0, 1, 2, …) | yeni `Array`, öğeler yinelemeli olarak dönüştürülür |
| diğer tüm `array` değerleri | yeni düz `Object`, değerler yinelemeli olarak dönüştürülür |
| `Closure`, çağrılabilir nesne, `[$object, 'method']` gibi çağrılabilir dizi | PHP çağrılabilirini çağıran `function` |
| diğer tüm nesneler, `Generator`, kaynak | `undefined` |

Karma anahtarlı diziler (PHP'ın `[0 => 'a', 'name' => 'b']` özelliği), düz nesnelere dönüşür; çünkü JS dizilerinde bitişik bir tamsayı indeks alanı bulunmalıdır.

```php
$engine->setGlobal('list', [1, 2, 3]);                 // → JS Array
$engine->setGlobal('map',  ['a' => 1, 'b' => 2]);      // → JS Object
$engine->setGlobal('mixed', [0 => 'x', 'k' => 'v']);   // → JS Object
```

Diziler kopyalandığından, JS değişiklikleri JS içinde kalır:

```php
$list = [1, 2, 3];
$engine->setGlobal('list', $list);
$engine->eval('list.push(4)');
count($list);                 // 3
$engine->eval('list.length'); // 4
```

Çağrılabilir olmayan PHP nesneleri dönüştürülmez; `undefined` olarak gelirler ([sorun #18](https://github.com/inline0/phasis/issues/18)). Önce dizilere dönüştürün; örneğin `get_object_vars()` kullanın veya yöntemlerini kapatmalar olarak sunun. Bkz. [Paylaşılan nesneler](https://phasis.inline0.dev/tr/docs/interop/shared-objects).

## JS → PHP: `eval()` ve `call()` sonuçları

| JS değeri | PHP sonucu |
|---|---|
| `undefined`, `null` | `null` |
| `boolean` | `bool` |
| `number` (tam sayı, int aralığında) | `int` (`-0`, `0` olur) |
| `NaN`, `Infinity`, `-Infinity` | `NAN`, `INF`, `-INF` |
| `number` (diğer) | `float` |
| `string` | `string` (UTF-8) |
| `bigint`, `symbol` | `null` |
| `function` | `null` |
| `Array` | liste `array`, öğeler yinelemeli olarak dönüştürülür |
| `TypedArray` | sayılardan oluşan liste `array` |
| diğer tüm nesneler (düz nesneler, `Error`, `Date`, `Map`, `Set`, `Promise`, `ArrayBuffer`, …) | kendi veri özelliklerini içeren ilişkisel `array`; erişimciler ve işlev değerli özellikler atlanır |

Son satır, durumu dahili yuvalarda bulunan nesnelerin boş bir diziye dönüştüğü anlamına gelir: `new Date(0)`, `new Map([["a", 1]])` ve `Promise.resolve(5)` tümü `[]` döndürür. Bir `Error` kendi `message` ve `stack` değerlerini döndürür. Kendine başvuran bir nesne, iç başvurularını `null` değerine dönüştürür.

```php
$engine->eval('[1, 2, 3]');                // [1, 2, 3]
$engine->eval('({a: 1, b: 2})');           // ['a' => 1, 'b' => 2]
$engine->eval('new Uint8Array([1, 2, 3])'); // [1, 2, 3]
$engine->eval('1234567890123456789n');     // null
$engine->eval('new Date(0)');              // []
```

Bu değerlerden birine PHP içinde ihtiyacınız varsa, JS içinde dönüştürün:

```php
$engine->eval('(1234567890123456789n).toString()');  // "1234567890123456789"
$engine->eval('new Date(0).toISOString()');           // "1970-01-01T00:00:00.000Z"
$engine->eval('Object.fromEntries(new Map([["a", 1]]))'); // ['a' => 1]
```

## JS → PHP: ana makine işlevi bağımsız değişkenleri

JS'ın bir PHP ana makine işlevine ilettiği bağımsız değişkenler; ilkel değerler, diziler ve düz nesneler için aynı kuralları izler, şu farklarla:

| JS değeri | PHP argümanı |
|---|---|
| `TypedArray`, `ArrayBuffer`, `DataView` | motorun kendi `JsValue` nesnesi, dönüştürülmeden |
| nesne | erişimciler (getter'ları çalıştırılır) ve işlev değerli özellikler dahil tüm kendi özelliklerini içeren ilişkisel `array` |
| ok işlevi | bir `array` (genellikle boş) |
| `function` anahtar sözcüğüyle tanımlanan `function` veya kendisine başvuran herhangi bir nesne | dönüştürme yapılamaz: kopyalama hiç bitmez ve PHP belleği tükenir ([sorun #21](https://github.com/inline0/phasis/issues/21)) |

Bir ana makine işlevinde henüz JS geri çağrısı alma yolu yoktur. Bu sınırdan işlev değil, veri geçirin.

## Sayılar ve hassasiyet

JavaScript sayıları IEEE 754 çift duyarlıklıdır. PHP int değerleri platformun yerel türündedir (her modern derlemede 64 bit). Dönüştürme, ±2^53'e kadar olan tamsayıları tam olarak korur; daha büyük PHP int değerleri `number` olur ve 16 ondalık basamaktan sonra hassasiyetini kaybeder. Bundan daha büyük tamsayılarda tam aritmetik gerekiyorsa JS içinde `BigInt` kullanın ve sonucu dizge olarak dışarı aktarın.

## Dizgeler

PHP dizgeleri bayt dizileridir; JS dizgeleri UTF-16 kod birimi dizileridir. Motor, PHP baytlarını UTF-8 olarak yorumlayıp dahili olarak UTF-16'ya yeniden kodlayarak aralarında köprü kurar. Geçerli UTF-8 girdilerinde bu işlem kayıpsızdır. Geçerli UTF-8 olmayan baytlar, U+FFFD ile değiştirilmek yerine değiştirilmeden aktarılır.

`String.length`, indeksli erişim (`s[0]`) ve dilimleme işlemlerinin tümü ECMAScript belirtimine göre UTF-16 kod birimlerini sayar; kod noktalarını veya baytları değil. Bu nedenle `'🍕'` gibi astral karakterler içeren dizgelerde `.length === 2` bulunur (U+1F355'in iki vekil yarısı).

## Gidiş dönüş kararlılığı

Düz veriler gidiş dönüşte korunur: `setGlobal()` üzerinden girip `eval()` veya `call()` üzerinden dönen, skaler değerlerden, listelerden ve ilişkisel dizilerden oluşan bir PHP değeri aynı yapıyı üretir; tam sayı değerindeki kayan noktalı sayılar `int` olarak geri döner (`1.0`, `1` döndürür).

Yukarıdaki tablolarda `null`, `undefined` veya `[]` ile eşlenen diğer hiçbir değer gidiş dönüşte korunmaz.
