Začíname
Inštalácia
composer require phasis/phasis
Phasis vyžaduje PHP 8.2 alebo novší a tri rozšírenia, ktoré všetky vyžaduje composer.json:
mbstring— práca s reťazcami.bcmath— aritmetika BigInt a spracovanie čísel s celočíselnou presnosťou.curl— predvolený prenosový mechanizmus prefetch().
mbstring a curl sú povolené vo väčšine zostáv. bcmath často chýba: oficiálne obrazy php Docker (php:8.x-cli, php:8.x-fpm) ho neobsahujú a niektoré distribúcie ho balia samostatne (php-bcmath). Bez neho Composer odmietne nainštalovať Phasis. Do Dockerfile založeného na oficiálnom obraze pridajte:
RUN docker-php-ext-install bcmath
Spustite php -m a zistite, ktoré rozšírenia obsahuje vaša zostava.
ext-intl je voliteľné. Phasis funguje aj bez neho, ale celá rodina Intl.* (Collator, NumberFormat, DateTimeFormat, PluralRules, Locale, DisplayNames, ListFormat, RelativeTimeFormat, Segmenter, DurationFormat) a kalendáre Temporal, ktoré nie sú ISO (hebrew, islamic, japanese, persian atď.), ho potrebujú. Nainštalujte ho vždy, keď hostiteľská aplikácia poskytuje JS pracujúce s formátovaním závislým od miestnych nastavení. Voliteľné je aj ext-openssl: šifrovanie AES-CBC, AES-CTR a AES-GCM cez crypto.subtle ho vyžaduje, kým súhrny a HMAC fungujú aj bez neho.
Bez exec, bez FFI, bez Node.js, bez vlastného natívneho rozšírenia.
Spustenie skriptu z CLI
./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 vypíše to, čo skript zapisuje pomocou console.log; hodnotu posledného výrazu nevypíše.
Úplný zoznam príkazov nájdete v referenčnej príručke CLI.
Vloženie do PHP
<?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
Inštancia Engine si medzi volaniami zachováva globálny stav, takže pri ďalších volaniach eval() budú k dispozícii všetky predtým definované prvky.
console.log a súvisiace funkcie pridávajú obsah do vyrovnávacej pamäte modulu namiesto zapisovania na stdout. Prečítajte ho pomocou getConsoleOutput() (jeden reťazec, riadky spojené pomocou \n) alebo getConsoleLines() (zoznam riadkov) a vymažte ho pomocou clearConsole().
Studený štart je rýchly: vopred sa nainštaluje iba jadro potrebné na načítanie špecifikácie (Object, Function, Array, Promise, Symbol, BigInt, RegExp a typy chýb). Map, TypedArray, Temporal, Intl, URL, fetch, úplné balíky Web Platform / Fetch aj všetko ostatné sa transparentne vytvoria pri prvom čítaní. Ak chcete pri vytváraní nainštalovať všetky vstavané prvky, odovzdajte new Engine(eager: true) — užitočné pre nástroje na kontrolu zhody, ktoré skúmajú deskriptory ešte pred čítaním; pri bežnom vkladacom použití je to zriedka potrebné.
Volanie funkcií JS z PHP
$engine->eval('function add(a, b) { return a + b; }');
echo $engine->call('add', 2, 3);
// 5
call() vyhľadá funkciu podľa názvu na globálnom objekte a zavolá ju s dodanými argumentmi PHP (automaticky prevedenými na hodnoty JS).
Sprístupnenie volateľnej funkcie PHP ako funkcie JS
$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")');
Uzávery PHP sa zabalia ako funkcie JS. Ich argumenty sa pri volaní prevedú z JS na PHP a návratové hodnoty sa prevedú späť z PHP na JS.
Objekty PHP
Objekty PHP zatiaľ nemožno zdieľať s JavaScript. setGlobal() s obyčajným objektom PHP naviaže undefined (sledované v probléme č. 18). Údaje odovzdávajte ako polia, ktoré sa skopírujú do JS, a správanie sprístupnite ako uzávery:
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
Podrobnosti a ďalšie riešenia nájdete v časti Zdieľané objekty.
Limity zdrojov
$engine = new Engine();
$engine->setLimit('maxLoopIterations', 100_000);
maxLoopIterations (predvolená hodnota 100,000) je jediný limit nastaviteľný počas behu programu a momentálne sa vzťahuje len na kód spúšťaný interpretom prechádzajúcim strom. Slučky spúšťané VM bajtkódu (telá funkcií a väčšina kódu najvyššej úrovne) sa nezapočítavajú, takže samotný limit nezastaví while (true) {} (problém č. 19). Po dosiahnutí limitu možno chybu zachytiť v JS; ak zostane nezachytená, dostane sa do PHP ako Phasis\Exceptions\InternalError, podtrieda Phasis\Exceptions\RuntimeError.
Modul má tiež pevný limit zásobníka volaní 4,096 rámcov (a ochranný limit 8,192 rámcov pre transpilované uzávery); jeho prekročenie vyvolá chybu „Maximum call stack size exceeded“, opäť ako InternalError. Časový limit v reálnom čase neexistuje, preto nedôveryhodný kód spúšťajte pod vlastným max_execution_time nástroja PHP alebo v samostatnom procese. Pozrite si API: setLimit.
Ďalšie kroky
- API referencia — úplné rozhranie
Phasis\Engine. - Prepojenie — pravidlá konverzie hodnôt, hostiteľské funkcie, objekty PHP.
- Kompatibilita — implementované funkcie a pokrytie test262.
- Analyzátor a Formátovač — analyzovanie a formátovanie JavaScript bez jeho spustenia.
- Rozšírené témy — architektúra, VM bajtkódu, testy výkonu a testovanie pomocou referenčnej implementácie.