Başlarken
Yükleme
composer require phasis/phasis
Phasis için, composer.json'nin gerektirdiği üç uzantıyla birlikte PHP 8.2 veya daha yenisi gerekir:
mbstring— dize işleme.bcmath— BigInt aritmetiği ve tamsayı hassasiyetinde sayı işleme.curl—fetch()arkasındaki varsayılan aktarım.
mbstring ve curl çoğu derlemede etkindir. bcmath ise çoğunlukla etkin değildir: resmi php Docker görüntülerinde (php:8.x-cli, php:8.x-fpm) bulunmaz ve bazı dağıtımlar bunu ayrı bir paket olarak sunar (php-bcmath). Bu olmadan Composer, Phasis'ın yüklenmesini reddeder. Resmi görüntüyü temel alan bir Dockerfile'a şunu ekleyin:
RUN docker-php-ext-install bcmath
Derlemenizde hangi uzantıların bulunduğunu görmek için php -m komutunu çalıştırın.
ext-intl isteğe bağlıdır. Phasis onsuz çalışır; ancak Intl.* ailesinin tamamı (Collator, NumberFormat, DateTimeFormat, PluralRules, Locale, DisplayNames, ListFormat, RelativeTimeFormat, Segmenter, DurationFormat) ve ISO olmayan Temporal takvimleri (hebrew, islamic, japanese, persian vb.) buna ihtiyaç duyar. Yerel ayarlara duyarlı biçimlendirmeye dokunan JS'ı barındıran uygulamalarda bunu yükleyin. ext-openssl de isteğe bağlıdır: AES-CBC, AES-CTR ve AES-GCM şifrelemesi için crypto.subtle gerekirken özetler ve HMAC onsuz çalışır.
exec yok, FFI yok, Node.js yok, özel yerel uzantı yok.
CLI üzerinden bir betik çalıştırma
./vendor/bin/phasis -e 'console.log(1 + 2 * 3)'
# 7
./vendor/bin/phasis -e 'console.log([1, 2, 3].map(x => x * x).join(","))'
# 1,4,9
./vendor/bin/phasis path/to/script.js
CLI, betiğin console.log ile yazdıklarını yazdırır; son ifadenin değerini yazdırmaz.
Tüm komutları görmek için CLI başvurusuna bakın.
PHP içine yerleştirme
<?php
require __DIR__ . '/vendor/autoload.php';
use Phasis\Engine;
$engine = new Engine();
// Evaluate an expression
$result = $engine->eval('1 + 2 * 3');
echo $result;
// 7
// Execute a script file
$engine->execFile('path/to/script.js');
// Bridge a PHP value into the JS global scope
$engine->setGlobal('config', ['debug' => true, 'version' => '1.0']);
$engine->eval('console.log(config.version)');
// console output is buffered on the engine, not printed
echo $engine->getConsoleOutput();
// 1.0
Engine örneği, çağrılar arasında küresel durumunu korur; böylece sonraki eval() çağrıları daha önce tanımladığınız her şeyi görür.
console.log ve benzerleri stdout'a yazmak yerine motor üzerindeki bir arabelleğe ekleme yapar. Arabelleği getConsoleOutput() ile (tek dize, satırlar \n ile birleştirilmiş) veya getConsoleLines() ile (satır listesi) okuyun; clearConsole() ile boşaltın.
Soğuk başlangıç maliyeti düşüktür: yalnızca belirtim yüklemesi için gerekli çekirdek (Object, Function, Array, Promise, Symbol, BigInt, RegExp ve hata türleri) başlangıçta yüklenir. Map, TypedArray, Temporal, Intl, URL, fetch, Web Platform / Fetch Packs'in tamamı ve diğer her şey ilk okumada şeffaf biçimde yüklenir. Yapıcı sırasında tüm yerleşik özellikleri yüklemek için new Engine(eager: true) değerini geçin; bu, tanımlayıcıları okumadan önce inceleyen uyumluluk araçları için kullanışlıdır, normal gömme işlemlerinde nadiren gerekir.
JS işlevlerini PHP üzerinden çağırma
$engine->eval('function add(a, b) { return a + b; }');
echo $engine->call('add', 2, 3);
// 5
call(), işlevi global nesnede adına göre bulur ve sağlanan PHP bağımsız değişkenlerle çağırır (otomatik olarak JS değerlerine dönüştürülür).
Bir PHP çağrılabilirini JS işlevi olarak sunma
$engine->setGlobal('fetchData', function (string $url): array {
return json_decode(file_get_contents($url), true);
});
$engine->eval('const users = fetchData("https://api.example.com/users")');
PHP closure'ları, JS işlevleri olarak sarmalanır. Çağrıldıklarında bağımsız değişkenleri JS'dan PHP'a dönüştürülür; dönüş değerleri ise PHP'ten JS'e geri dönüştürülür.
PHP nesneleri
PHP nesneleri henüz JavaScript ile paylaşılamaz. Düz bir PHP nesnesiyle setGlobal(), undefined'ı bağlar (issue #18 başlığında izleniyor). Verileri JS içine kopyalanan diziler olarak aktarın ve davranışı closure'lar olarak sunun:
class Counter {
public int $value = 0;
public function increment(): void { $this->value++; }
}
$counter = new Counter();
$engine->setGlobal('increment', fn () => $counter->increment());
$engine->eval('increment(); increment();');
echo $counter->value;
// 2
Ayrıntılar ve diğer geçici çözümler için Paylaşılan nesneler bölümüne bakın.
Kaynak sınırları
$engine = new Engine();
$engine->setLimit('maxLoopIterations', 100_000);
maxLoopIterations (varsayılanı 100,000), çalışma zamanında ayarlanabilen tek sınırdır ve şu an yalnızca ağaç üzerinde yürüyen yorumlayıcının çalıştırdığı kod için geçerlidir. Bayt kodu VM'nin çalıştırdığı döngüler (işlev gövdeleri ve üst düzey kodun çoğu) sayılmaz; bu nedenle tek başına bir sınır while (true) {}'ı durdurmaz (issue #19). Sınıra ulaşıldığında hata JS içinde yakalanabilir; yakalanmazsa PHP'e Phasis\Exceptions\RuntimeError alt sınıfı olan Phasis\Exceptions\InternalError olarak ulaşır.
Motorun ayrıca sabit bir 4,096 çerçeveli çağrı yığını tavanı (ve transpile edilmiş closure'lar için 8,192 çerçeveli bir koruması) vardır; bu sınır aşılırsa yine InternalError olarak "Maximum call stack size exceeded" hatası fırlatılır. Duvar saati sınırı yoktur; bu nedenle güvenilmeyen kodu PHP'ın kendi max_execution_time'ı altında veya ayrı bir süreçte çalıştırın. Bkz. API: setLimit.
Sonraki adımlar
- API başvurusu — tüm
Phasis\Enginearayüzü. - Birlikte çalışabilirlik — değer dönüştürme kuralları, ana uygulama işlevleri, PHP nesneleri.
- Uyumluluk — nelerin uygulandığı, test262 kapsamı.
- Ayrıştırıcı ve Biçimlendirici — JavaScript kodunu çalıştırmadan ayrıştırın ve biçimlendirin.
- Gelişmiş — mimari, bayt kodu VM, kıyaslamalar, oracle testleri.