Darba sākšana
Instalēšana
composer require phasis/phasis
Phasis vajadzīgs PHP 8.2 vai jaunāks ar trim paplašinājumiem, kas visi nepieciešami composer.json:
mbstring— virkņu apstrāde.bcmath— BigInt aritmētika un veselu skaitļu precizitātes skaitļu apstrāde.curl— noklusētais transports, ko izmantofetch().
mbstring un curl ir iespējoti lielākajā daļā būvējumu. bcmath bieži nav pieejams: oficiālajos php Docker attēlos (php:8.x-cli, php:8.x-fpm) tas nav iekļauts, un daži izplatījumi to piedāvā atsevišķā pakotnē (php-bcmath). Bez tā Composer atsakās instalēt Phasis. Dockerfile, kura pamatā ir oficiālais attēls, pievienojiet:
RUN docker-php-ext-install bcmath
Palaidiet php -m, lai noskaidrotu, kādi paplašinājumi ir iekļauti jūsu būvējumā.
ext-intl nav obligāts. Phasis darbojas arī bez tā, taču visai Intl.* saimei (Collator, NumberFormat, DateTimeFormat, PluralRules, Locale, DisplayNames, ListFormat, RelativeTimeFormat, Segmenter, DurationFormat) un Temporal kalendāriem, kas nav ISO (hebrew, islamic, japanese, persian u.c.), tas ir nepieciešams. Instalējiet to, ja resursdatora lietotne nodrošina JS, kas izmanto lokalizācijai pielāgotu formatēšanu. ext-openssl arī nav obligāts: crypto.subtle AES-CBC, AES-CTR un AES-GCM šifrēšanai tas ir nepieciešams, bet jaucējvērtību aprēķināšana un HMAC darbojas arī bez tā.
Nav exec, FFI, Node.js vai pielāgotu vietējo paplašinājumu.
Skripta palaišana no 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 izvada to, ko skripts raksta, izmantojot console.log; tas neizvada pēdējās izteiksmes vērtību.
Pilno komandu kopuma skatiet CLI atsaucē.
Iegulšana 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 instance starp izsaukumiem saglabā savu globālo stāvokli, tāpēc turpmākajos eval() izsaukumos ir pieejams viss iepriekš definētais.
console.log un tā radniecīgās funkcijas pievieno datus dzinēja buferim, nevis raksta uz stdout. Nolasiet to ar getConsoleOutput() (viena virkne, rindas savienotas ar \n) vai getConsoleLines() (rindu saraksts) un iztukšojiet ar clearConsole().
Aukstā startēšana ir lēta: sākumā tiek instalēts tikai specifikācijas ielādei nepieciešamais kodols (Object, Function, Array, Promise, Symbol, BigInt, RegExp un kļūdu tipi). Map, TypedArray, Temporal, Intl, URL, fetch, pilnās Web Platform / Fetch pakotnes un viss pārējais tiek nemanāmi ielādēts pirmajā nolasīšanas reizē. Nododiet new Engine(eager: true), lai izveides laikā instalētu visas iebūvētās funkcijas — noder atbilstības pārbaudes rīkiem, kas pārbauda deskriptorus pirms to nolasīšanas; parasti iegulšanai tas nav vajadzīgs.
JS funkciju izsaukšana no PHP
$engine->eval('function add(a, b) { return a + b; }');
echo $engine->call('add', 2, 3);
// 5
call() meklē funkciju pēc nosaukuma globālajā objektā un izsauc to ar norādītajiem PHP argumentiem (kas tiek automātiski pārveidoti par JS vērtībām).
PHP izsaucamās funkcijas atklāšana kā JS funkcija
$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 slēgumi tiek ietīti kā JS funkcijas. Izsaukšanas brīdī argumenti no JS tiek pārveidoti par PHP, bet atgrieztās vērtības no PHP tiek pārveidotas atpakaļ par JS.
PHP objekti
PHP objektus pagaidām nevar koplietot ar JavaScript. setGlobal() sasaista undefined, ja tam nodod parastu PHP objektu (tas tiek izsekots kā issue #18). Nododiet datus kā masīvus, kas tiek kopēti uz JS, un atklājiet darbības kā slēgumus:
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
Plašāku informāciju un citus risinājumus skatiet sadaļā Koplietoti objekti.
Resursu ierobežojumi
$engine = new Engine();
$engine->setLimit('maxLoopIterations', 100_000);
maxLoopIterations (noklusējuma vērtība 100,000) ir vienīgais izpildlaikā pielāgojamais ierobežojums, un pašlaik tas attiecas tikai uz kodu, ko izpilda koka šķērsošanas interpretētājs. Baitu koda virtuālās mašīnas izpildītās cilpas (funkciju pamatdaļas un lielākā daļa augstākā līmeņa koda) netiek skaitītas, tāpēc ar šo ierobežojumu vien nepietiek, lai apturētu while (true) {} (issue #19). Sasniedzot ierobežojumu, kļūdu var uztvert ar JS; ja tā netiek uztverta, tā nonāk līdz PHP kā Phasis\Exceptions\InternalError, kas ir Phasis\Exceptions\RuntimeError apakšklase.
Dzinējam ir arī fiksēts izsaukumu steka ierobežojums — 4,096 kadri (un transpiletiem slēgumiem paredzēta 8,192 kadru aizsardzība); tā pārsniegšana izraisa kļūdu "Maximum call stack size exceeded", atkal kā InternalError. Laika ierobežojuma nav, tāpēc neuzticamu kodu palaidiet ar PHP paša max_execution_time vai atsevišķā procesā. Skatiet API: setLimit.
Nākamās darbības
- API atsauce — pilns
Phasis\Engineiespēju klāsts. - Savietojamība — vērtību pārveidošanas noteikumi, resursdatora funkcijas, PHP objekti.
- Saderība — ieviestās funkcijas un test262 pārklājums.
- Parsētājs un Formatētājs — parsējiet un formatējiet JavaScript, to neizpildot.
- Papildu informācija — arhitektūra, baitu koda virtuālā mašīna, etalonmērījumi un orākula testēšana.