Aloitus
Asennus
composer require phasis/phasis
Phasis tarvitsee PHP version 8.2 tai uudemman sekä kolme laajennusta, joita kaikkia composer.json edellyttää:
mbstring— merkkijonojen käsittely.bcmath— BigInt-aritmetiikka ja kokonaislukujen tarkka käsittely.curl— oletusarvoinen siirtofetch()-toiminnon taustalla.
mbstring ja curl ovat käytössä useimmissa koontiversioissa. bcmath usein puuttuu: virallisista php Docker-näköistiedostoista (php:8.x-cli, php:8.x-fpm) se on jätetty pois, ja joissakin jakeluissa se paketoidaan erikseen (php-bcmath). Ilman sitä Composer kieltäytyy asentamasta kohdetta Phasis. Lisää viralliseen näköistiedostoon perustuvaan Dockerfileen:
RUN docker-php-ext-install bcmath
Suorita php -m nähdäksesi, mitkä laajennukset koontiversiossasi ovat käytössä.
ext-intl on valinnainen. Phasis toimii ilman sitä, mutta koko Intl.*-perhe (Collator, NumberFormat, DateTimeFormat, PluralRules, Locale, DisplayNames, ListFormat, RelativeTimeFormat, Segmenter, DurationFormat, ISO) sekä muut kuin hebrew-kalenterit Temporalissa (islamic, japanese, persian jne.) tarvitsevat sitä. Asenna se aina, kun isäntäsovellus tarjoaa JS-toiminnon, joka käsittelee paikallisasetusten mukaista muotoilua. Myös ext-openssl on valinnainen: crypto.subtle tarvitaan AES-CBC-, AES-CTR- ja AES-GCM-salaukseen, mutta digestit ja HMAC toimivat ilman sitä.
Ei exec:ta, FFI:tä, Node.js:tä eikä mukautettuja natiivilaajennuksia.
Suorita skripti kohteesta 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 tulostaa sen, mitä skripti kirjoittaa toiminnolla console.log; se ei tulosta viimeisen lausekkeen arvoa.
Katso CLI viitteestä koko komentovalikoima.
Upottaminen kohteeseen 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
Engine-instanssi säilyttää globaalin tilansa kutsujen välillä, joten myöhemmät eval()-kutsut näkevät kaiken aiemmin määrittelemäsi.
console.log ja sen sisarfunktiot lisäävät sisältöä moottorin puskuriin stdoutiin kirjoittamisen sijaan. Lue se funktiolla getConsoleOutput() (yksi merkkijono, rivit yhdistetty merkillä \n) tai getConsoleLines() (rivilista) ja tyhjennä se funktiolla clearConsole().
Kylmäkäynnistys on edullinen: aluksi asennetaan vain määrittelyjen lataamisesta vastaava ydin (Object, Function, Array, Promise, Symbol, BigInt, RegExp ja virhetyypit). Map, TypedArray, Temporal, Intl, URL, fetch, täydet Web Platform- ja Fetch-paketit sekä kaikki muu alustetaan läpinäkyvästi ensimmäisellä lukukerralla. Asenna kaikki sisäänrakennetut konstruktion yhteydessä välittämällä new Engine(eager: true) — hyödyllistä vaatimustenmukaisuustyökaluissa, jotka tarkastelevat kuvauksia ennen niiden lukemista; tavallisessa upotuksessa sitä tarvitaan harvoin.
Kutsu JS-funktioita kohteesta PHP
$engine->eval('function add(a, b) { return a + b; }');
echo $engine->call('add', 2, 3);
// 5
call() etsii funktion nimellä globaalista oliosta ja kutsuu sitä annetuilla PHP-argumenteilla (jotka muunnetaan automaattisesti JS-arvoiksi).
Aseta kohteen PHP kutsuttava kohteen JS funktioksi
$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-sulkeumat kääritään JS-funktioiksi. Kutsussa niiden argumentit muunnetaan tyypistä JS tyyppiin PHP, ja paluuarvot muunnetaan takaisin tyypistä PHP tyyppiin JS.
PHP-oliot
PHP-olioita ei vielä voi jakaa kohteen JavaScript kanssa. setGlobal() tavallisen PHP-olion kanssa sitoo kohteen undefined (seuranta: issue #18). Välitä tiedot taulukoina, jotka kopioidaan kohteeseen JS, ja tuo toiminnallisuus saataville sulkeumina:
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
Katso Jaetut oliot-sivulta lisätietoja ja muita kiertotapoja.
Resurssirajat
$engine = new Engine();
$engine->setLimit('maxLoopIterations', 100_000);
maxLoopIterations (oletus 100,000) on ainoa ajonaikaisesti säädettävä rajoitus, ja nykyään se koskee vain koodia, jota puuta kulkeva tulkki suorittaa. Tavutavun VM:n suorittamia silmukoita (funktioiden rungot ja suurin osa ylätason koodista) ei lasketa, joten pelkkä rajoitus ei estä while (true) {}-tilannetta (issue #19). Kun raja saavutetaan, virheen voi ottaa kiinni kohteessa JS; jos sitä ei käsitellä, se päätyy kohteeseen PHP muodossa Phasis\Exceptions\InternalError, joka on kohteen Phasis\Exceptions\RuntimeError aliluokka.
Moottorissa on myös kiinteä 4,096-kehysten kutsupinon yläraja (ja transpiloiduille sulkeumille 8,192-kehyksen suoja); sen ylittäminen aiheuttaa virheen "Maximum call stack size exceeded", jälleen muodossa InternalError. Seinäaikarajaa ei ole, joten suorita epäluotettua koodia kohteen PHP omassa max_execution_time-ympäristössä tai erillisessä prosessissa. Katso API: setLimit.
Seuraavat vaiheet
- API-viite — koko
Phasis\Engine-rajapinta. - Yhteentoimivuus — arvojen muuntosäännöt, isäntäfunktiot ja PHP-oliot.
- Yhteensopivuus — toteutetut ominaisuudet ja test262-kattavuus.
- Jäsennin ja Muotoilija — jäsennä ja muotoile JavaScript suorittamatta sitä.
- Lisäominaisuudet — arkkitehtuuri, tavukoodi-VM, vertailutestit ja oraakkelitestaus.