
# Aloitus

## Asennus

```bash
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

```bash
./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ä](https://phasis.inline0.dev/fi/docs/cli) 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](https://github.com/inline0/phasis/issues/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](https://phasis.inline0.dev/fi/docs/interop/shared-objects)-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](https://github.com/inline0/phasis/issues/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](https://phasis.inline0.dev/fi/docs/api#setlimit).

## Seuraavat vaiheet

- [API-viite](https://phasis.inline0.dev/fi/docs/api) — koko `Phasis\Engine`-rajapinta.
- [Yhteentoimivuus](https://phasis.inline0.dev/fi/docs/interop) — arvojen muuntosäännöt, isäntäfunktiot ja PHP-oliot.
- [Yhteensopivuus](https://phasis.inline0.dev/fi/docs/compatibility) — toteutetut ominaisuudet ja test262-kattavuus.
- [Jäsennin](https://phasis.inline0.dev/fi/docs/parser) ja [Muotoilija](https://phasis.inline0.dev/fi/docs/formatter) — jäsennä ja muotoile JavaScript suorittamatta sitä.
- [Lisäominaisuudet](https://phasis.inline0.dev/fi/docs/advanced) — arkkitehtuuri, tavukoodi-VM, vertailutestit ja oraakkelitestaus.
