
# Začetek

## Namestitev

```bash
composer require phasis/phasis
```

Phasis potrebuje PHP 8.2 ali novejšo različico s tremi razširitvami, ki jih vse zahteva `composer.json`:

- `mbstring` — obdelava nizov.
- `bcmath` — aritmetika BigInt in obdelava števil z natančnostjo celih števil.
- `curl` — privzeti transport za `fetch()`.

`mbstring` in `curl` sta omogočena v večini različic. `bcmath` pa pogosto ni: uradne slike `php` Docker (`php:8.x-cli`, `php:8.x-fpm`) ga ne vključujejo, nekatere distribucije pa ga ponujajo ločeno (`php-bcmath`). Brez njega Composer zavrne namestitev Phasis. V Dockerfile, ki temelji na uradni sliki, dodajte:

```dockerfile
RUN docker-php-ext-install bcmath
```

Zaženite `php -m`, da preverite, katere razširitve so na voljo v vaši različici.

`ext-intl` ni obvezen. Phasis deluje tudi brez njega, vendar ga potrebuje celotna družina `Intl.*` (`Collator`, `NumberFormat`, `DateTimeFormat`, `PluralRules`, `Locale`, `DisplayNames`, `ListFormat`, `RelativeTimeFormat`, `Segmenter`, `DurationFormat`) ter koledarji, ki niso ISO (`hebrew`, `islamic`, `japanese`, `persian` itd.) Temporal. Namestite ga, kadar gostiteljska aplikacija omogoča JS, ki uporabljajo oblikovanje, prilagojeno področne nastavitve. Tudi `ext-openssl` ni obvezen: za šifriranje AES-CBC, AES-CTR in AES-GCM ga potrebuje `crypto.subtle`, medtem ko zgoščevalne funkcije in HMAC delujejo brez njega.

Brez `exec`, brez FFI, brez Node.js, brez lastne izvorne razširitve.

## Zaženite skript iz 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 izpiše, kar skript zapiše z `console.log`; vrednosti zadnjega izraza ne izpiše.

Za celoten nabor ukazov glejte [CLI](https://phasis.inline0.dev/sl/docs/cli).

## Vdelava v 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
```

Instanca `Engine` med klici ohrani svoje globalno stanje, zato poznejši klici `eval()` vidijo vse, kar ste določili prej.

`console.log` in sorodne funkcije dodajajo vsebino v medpomnilnik v mehanizmu, namesto da bi jo zapisovale v stdout. Preberite ga z `getConsoleOutput()` (en niz, vrstice so združene z `\n`) ali `getConsoleLines()` (seznam vrstic), izpraznite pa z `clearConsole()`.

Hladen zagon je poceni: vnaprej se namesti samo jedro, ki nosi specifikacije (`Object`, `Function`, `Array`, `Promise`, `Symbol`, `BigInt`, `RegExp`, vrste napak). `Map`, `TypedArray`, `Temporal`, `Intl`, `URL`, `fetch`, celotni paketi Web Platform in Fetch ter vse drugo se pregledno ustvarijo ob prvem branju. Podajte `new Engine(eager: true)`, da se ob izdelavi namestijo vse vgrajene komponente — uporabno za orodja za preverjanje skladnosti, ki pregledajo deskriptorje, preden jih preberejo; pri običajni vdelavi je to redko potrebno.

## Klicanje funkcij JS iz PHP

```php
$engine->eval('function add(a, b) { return a + b; }');
echo $engine->call('add', 2, 3);
// 5
```

`call()` poišče funkcijo po imenu v globalnem objektu in jo pokliče s podanimi argumenti PHP (samodejno pretvorjenimi v vrednosti JS).

## Izpostavitev klicljive funkcije PHP kot funkcije JS

```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")');
```

Zaprtja PHP so ovita kot funkcije JS. Ob klicu se njihovi argumenti pretvorijo iz JS v PHP, vrnjene vrednosti pa nazaj iz PHP v JS.

## Objekti PHP

Objektov PHP še ni mogoče deliti z JavaScript. `setGlobal()` z navadnim objektom PHP veže `undefined` (spremljano v [težavi #18](https://github.com/inline0/phasis/issues/18)). Podatke posredujte kot polja, ki se kopirajo v JS, obnašanje pa izpostavite kot zaprtja:

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

Podrobnosti in druge rešitve najdete v razdelku [Skupni objekti](https://phasis.inline0.dev/sl/docs/interop/shared-objects).

## Omejitve virov

```php
$engine = new Engine();
$engine->setLimit('maxLoopIterations', 100_000);
```

`maxLoopIterations` (privzeta vrednost 100,000) je edina omejitev, ki jo je mogoče nastavljati med izvajanjem, trenutno pa velja samo za kodo, ki jo izvaja tolmač s sprehodom po drevesu. Zanke, ki jih izvaja bajtkodna navidezna naprava (telesa funkcij in večina vrhnjenivojske kode), se ne štejejo, zato sama omejitev ne ustavi `while (true) {}` ([težava #19](https://github.com/inline0/phasis/issues/19)). Ko je omejitev dosežena, lahko napako prestrežete v JS; če je ne prestrežete, doseže PHP kot `Phasis\Exceptions\InternalError`, podrazred `Phasis\Exceptions\RuntimeError`.

Mehanizem ima tudi fiksno omejitev klicnega sklada na 4,096 okvirjev (in varovalo na 8,192 okvirjev za transpajlirana zaprtja); ob prekoračitvi se sproži »Maximum call stack size exceeded«, znova kot `InternalError`. Časovna omejitev ne obstaja, zato nezaupanja vredno kodo izvajajte v lastnem PHP `max_execution_time` ali v ločenem procesu. Glejte [API: setLimit](https://phasis.inline0.dev/sl/docs/api#setlimit).

## Naslednji koraki

- [API](https://phasis.inline0.dev/sl/docs/api) — celoten nabor funkcij `Phasis\Engine`.
- [Sodelovanje](https://phasis.inline0.dev/sl/docs/interop) — pravila pretvorbe vrednosti, gostiteljske funkcije, objekti PHP.
- [Združljivost](https://phasis.inline0.dev/sl/docs/compatibility) — kaj je implementirano, pokritost z test262.
- [Razčlenjevalnik](https://phasis.inline0.dev/sl/docs/parser) in [Oblikovalnik](https://phasis.inline0.dev/sl/docs/formatter) — razčlenjevanje in oblikovanje JavaScript brez izvajanja.
- [Napredno](https://phasis.inline0.dev/sl/docs/advanced) — arhitektura, bajtkodna navidezna naprava, primerjalna merila in testiranje z orakljem.
