Siirry sisältöön

Aloitus

Asennus

Shell
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 siirto fetch()-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:

Dockerfile
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

Shell
./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
<?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

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

PHP
$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:

PHP
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

PHP
$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