Alustamine
Paigaldamine
composer require phasis/phasis
Phasis vajab versiooni PHP 8.2 või uuemat ning kolme laiendust, mida kõiki nõuab composer.json:
mbstring— stringide töötlemine.bcmath— BigInt-aritmeetika ja täisarvude täppisarvutus.curl— vaikeedastus, mida kasutabfetch().
mbstring ja curl on enamikus järkudes lubatud. bcmath sageli pole: ametlikud php Docker-kujutised (php:8.x-cli, php:8.x-fpm) jätavad selle välja ning osa distributsioone pakendab selle eraldi (php-bcmath). Ilma selleta keeldub Composer paketti Phasis installimast. Ametlikul kujutisel põhinevas Dockerfile'is lisage:
RUN docker-php-ext-install bcmath
Käivitage php -m, et näha, millised laiendused teie järgus olemas on.
ext-intl on valikuline. Phasis töötab selleta, kuid kogu Intl.*-perekond (Collator, NumberFormat, DateTimeFormat, PluralRules, Locale, DisplayNames, ListFormat, RelativeTimeFormat, Segmenter, DurationFormat) ja mitte-ISO Temporal-kalendrid (hebrew, islamic, japanese, persian jne) vajavad seda. Installige see siis, kui hostrakendus pakub JS, mis kasutab lokaaditeadlikku vormindamist. ext-openssl on samuti valikuline: crypto.subtle AES-CBC, AES-CTR ja AES-GCM-krüpteerimine vajab seda, räsid ja HMAC toimivad selleta.
Pole vaja exec, FFI-d, Node.js ega kohandatud natiivlaiendust.
Skripti käivitamine CLI-ist
./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 väljastab selle, mida skript kirjutab käsuga console.log; viimase avaldise väärtust see ei väljasta.
Vaadake täielikku käskude loendit CLI viite lehelt.
Manustamine PHP-isse
<?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 eksemplar säilitab kutsete vahel globaalse oleku, seega näevad järgnevad eval() väljakutsed kõike varem defineeritut.
console.log ja selle sõsarmeetodid lisavad väljundi mootori puhvrisse, mitte stdout'i. Lugege seda käsuga getConsoleOutput() (üks string, read ühendatud märgiga \n) või getConsoleLines() (ridade loend) ning tühjendage käsuga clearConsole().
Käivituse algkulu on väike: esmalt paigaldatakse ainult spetsifikatsiooni laadimist võimaldav tuum (Object, Function, Array, Promise, Symbol, BigInt, RegExp ja veatüübid). Map, TypedArray, Temporal, Intl, URL, fetch, täielikud Web Platformi ja Fetchi paketid ning kõik muu laaditakse esmakordsel lugemisel läbipaistvalt. Andke konstruktorile new Engine(eager: true), et paigaldada loomisel kõik sisseehitatud komponendid — kasulik vastavustööriistadele, mis uurivad deskriptoreid enne lugemist; tavalisel manustamisel läheb seda harva vaja.
Funktsioonide JS väljakutsumine PHP-ist
$engine->eval('function add(a, b) { return a + b; }');
echo $engine->call('add', 2, 3);
// 5
call() otsib funktsiooni nime järgi globaalobjektilt ja kutsub selle välja antud PHP argumentidega (teisendades need automaatselt JS väärtusteks).
PHP-i kutsutava muutmine JS funktsiooniks
$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 sulgurid mähitakse JS funktsioonideks. Väljakutse korral teisendatakse argumendid JS-ist PHP-ks ja tagastusväärtused PHP-st JS-ks.
PHP objektid
PHP objekte ei saa veel jagada JavaScript-iga. Tavalisel PHP objektil põhinev setGlobal() seob undefined-i (jälgitud teemas #18). Andke andmed edasi massiividena, mis kopeeritakse väärtuseks JS, ja tehke käitumine kättesaadavaks sulguritena:
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
Üksikasju ja muid lahendusi leiate lehelt Jagatud objektid.
Ressursipiirangud
$engine = new Engine();
$engine->setLimit('maxLoopIterations', 100_000);
maxLoopIterations (vaikimisi 100,000) on ainus käitusajal muudetav piirang ning praegu kehtib see ainult koodile, mida käivitab puud läbiv interpretaator. Baidikoodi VM-i käivitatavaid tsükleid (funktsioonide kehi ja enamikku tipptaseme koodi) ei loendata, seega piirang üksi ei peata while (true) {}-i (teema #19). Piirangu saavutamisel saab vea JS-is kinni püüda; püüdmata vea korral jõuab see PHP-ni kui Phasis\Exceptions\InternalError, mis on Phasis\Exceptions\RuntimeError alamklass.
Mootoril on ka fikseeritud 4,096-raamiline väljakutsepinu ülempiir (ning transpileeritud sulgurite jaoks 8,192-raamiline kaitse); selle ületamine põhjustab taas InternalError kujul vea "Maximum call stack size exceeded". Seinalähedast ajalimiiti pole, seega käivitage usaldamata kood PHP enda max_execution_time-is või eraldi protsessis. Vt API: setLimit.
Järgmised sammud
- API viide — täielik
Phasis\Engine-i funktsioonistik. - Koostalitlus — väärtuste teisendamise reeglid, hostfunktsioonid, PHP objektid.
- Ühilduvus — rakendatud funktsioonid, test262 katvus.
- Parser ja Vormindaja — JavaScript parsimine ja vormindamine seda käivitamata.
- Täpsem teave — arhitektuur, baidikoodi VM, võrdlusalused, võrdlustestimine.