Ana makine işlevleri
setGlobal() aracılığıyla motora verilen herhangi bir PHP kapanımı veya çağrılabilir işlevi, çağrılabilir bir JS işlevine dönüşür. Elle kayıt adımı, şema veya sıralama yoktur — çağrılabilir işlevi vermeniz yeterlidir.
Temel bilgiler
$engine->setGlobal('greet', function (string $name): string {
return "Hello, $name!";
});
echo $engine->eval('greet("world")');
// Hello, world!
greet("world"), JS içinde çalıştığında:
"world"dizesi JS biçiminden PHP biçimine dönüştürülür.- PHP kapanımı dönüştürülmüş bağımsız değişkenle çağrılır.
- Dönüş değeri PHP biçiminden tekrar JS biçimine dönüştürülür.
Dönüştürme, değer dönüştürme kurallarını izler. Bağımsız değişkenler kopyadır: JS dizisi veya nesnesi, yeni bir PHP dizisi olarak gelir ve PHP içinde bunu değiştirmek JS değerini değiştirmez.
Arite ve parametreler
Motor, JS bağımsız değişkenleri oldukları gibi, sırayla çağrılabilir işleve aktarır; imzayı incelemez. Fazladan bağımsız değişkenler sıradan kapanımlar tarafından yok sayılır, değişken sayıda bağımsız değişken alan parametrelerde toplanır. Eksikler tamamlanmaz: JS çağrılabilir işlevin gerektirdiğinden az bağımsız değişken aktarırsa PHP, ArgumentCountError fırlatır. İsteğe bağlı parametrelere varsayılan değerler verin.
$engine->setGlobal('format', function (string $template, ...$args): string {
return vsprintf($template, $args);
});
echo $engine->eval('format("%s is %d years old", "Ada", 36)');
// Ada is 36 years old
Tür dönüşümleri
Bağımsız değişkenler, JS→PHP kuralları kullanılarak PHP biçimine dönüştürülür. Motor, çağrılabilir işlevinizi strict_types=1 bildiren bir koddan çağırır; bu nedenle PHP skaler parametre türlerini katı biçimde denetler ve tür dönüşümü yapmaz: string parametresine aktarılan bir JS sayı, TypeError olur. Ana makine işlevindeki diğer PHP istisnaları gibi, bu da JS yerine eval() çağrısının sahibine ulaşır (aşağıya bakın).
$engine->setGlobal('len', fn(string $s): int => strlen($s));
$engine->eval('len(42)'); // PHP TypeError: Argument #1 ($s) must be of type string, int given
Kapanım içinde elle dönüştürme yapın ((string) $value) veya birleşim türleri kullanın (int|string).
JS tarafına hata fırlatma
Bir ana makine işlevi içinde fırlatılan sıradan PHP istisnaları bugün JS hatalarına dönüştürülmez. Tüm JS try / catch ve .catch() işleyicilerinden geçerek, özgün sınıflarıyla call() veya eval() çağıran PHP koduna ulaşırlar (sorun #20). Buna \Exception, \RuntimeException, \DivisionByZeroError ve hatalı bağımsız değişkenler için \TypeError ile \ArgumentCountError PHP hataları da dahildir.
$engine->setGlobal('divide', function (int $a, int $b): int {
if ($b === 0) {
throw new \DivisionByZeroError('cannot divide by zero');
}
return intdiv($a, $b);
});
try {
$engine->eval('
try { divide(10, 0); } catch (e) { /* never runs */ }
');
} catch (\DivisionByZeroError $e) {
echo $e->getMessage(); // cannot divide by zero
}
JS kodunun yakalayabileceği bir hata oluşturmak için motorun kendi hata sınıflarından birini fırlatın: Phasis\Exceptions\TypeError, RangeError veya ReferenceError, JS içinde eşleşen JS hata türü olarak gelir; diğer tüm Phasis\Exceptions\RuntimeError değerleri ileti metninizle düz bir Error olarak gelir.
use Phasis\Exceptions\RangeError;
$engine->setGlobal('divide', function (int $a, int $b): int {
if ($b === 0) {
throw new RangeError('cannot divide by zero');
}
return intdiv($a, $b);
});
$engine->eval('
try {
divide(10, 0);
} catch (e) {
console.log(e.name, e.message); // RangeError cannot divide by zero
}
');
Zengin değerler döndürme
Dönüş değeri PHP→JS kurallarıyla dönüştürülür. Bir JS nesne sabiti döndürmek için PHP ilişkisel dizisi döndürün:
$engine->setGlobal('lookup', function (string $key): array {
return ['key' => $key, 'value' => 42, 'meta' => ['ts' => time()]];
});
$engine->eval('
const r = lookup("answer");
console.log(r.value, r.meta.ts);
');
Bir JS dizisi döndürmek için sıralı bir PHP listesi döndürün:
$engine->setGlobal('range', fn(int $a, int $b): array => range($a, $b));
$engine->eval('range(1, 5).reduce((a, b) => a + b)'); // 15
ReactPHP, Amp veya Guzzle kaynaklı PHP promise da dahil olmak üzere bir PHP nesnesi döndürmek, JS undefined sonucunu verir (bkz. Değer dönüştürme).
Eşzamansız ana makine işlevleri
Ana makine işlevleri eşzamanlıdır. Bir PHP promise veya başka bir thenable nesnesi beklenmez: undefined biçimine dönüştürülür ve bu nedenle await hostFn(), undefined sonucuna çözülür. İşi eşzamanlı yapıp sonucu döndürün; JS kodu çağrıyı yine de await yapabilir; bu, değeri çözülmüş bir promise içine sarar:
$engine->setGlobal('loadBody', function (string $url): string {
return file_get_contents($url);
});
$engine->eval('
async function main() {
const body = await loadBody("https://example.com");
console.log(body.length);
}
main();
');
Özellikle HTTP için yerleşik fetch() zaten gerçek bir JS promise döndürür ve özel fetch aktarımı ile kendi PHP istemciniz üzerinden yönlendirilebilir.
Performans notları
Her ana makine işlevi çağrısı, bağımsız değişkenler için PHP↔JS sınırını bir kez, dönüş değeri için de bir kez geçer. Her iki dönüştürme de kopyalama yapar ve bu yüzden O(size of value) maliyetlidir — ilkel değerler sabit zamanda, diziler ve nesneler ise boyutlarıyla orantılı sürede işlenir.
Sık çalışan iç döngülerde, çok sayıda küçük çağrı yerine daha fazla iş yapan tek bir çağrıyı tercih edin ve yalnızca birkaç alan değişirken büyük dizileri gidip gelmek üzere aktarmaktan kaçının.