
# Pierwsze kroki

## Instalacja

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

Phasis wymaga PHP 8.2 lub nowszej oraz trzech rozszerzeń, których wszystkie wymaga `composer.json`:

- `mbstring` — obsługa ciągów znaków.
- `bcmath` — arytmetyka BigInt i obsługa liczb z precyzją całkowitą.
- `curl` — domyślny transport używany przez `fetch()`.

`mbstring` i `curl` są włączone w większości kompilacji. `bcmath` często nie jest: oficjalne obrazy `php` Docker (`php:8.x-cli`, `php:8.x-fpm`) go nie zawierają, a niektóre dystrybucje udostępniają je osobno (`php-bcmath`). Bez niego Composer odmawia instalacji Phasis. W pliku Dockerfile opartym na oficjalnym obrazie dodaj:

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

Uruchom `php -m`, aby sprawdzić, które rozszerzenia zawiera Twoja kompilacja.

`ext-intl` jest opcjonalne. Phasis działa bez niego, ale potrzebuje go cała rodzina `Intl.*` (`Collator`, `NumberFormat`, `DateTimeFormat`, `PluralRules`, `Locale`, `DisplayNames`, `ListFormat`, `RelativeTimeFormat`, `Segmenter`, `DurationFormat`) oraz kalendarze Temporal inne niż ISO (`hebrew`, `islamic`, `japanese`, `persian` itd.). Zainstaluj je, jeśli aplikacja hosta udostępnia JS, które wykorzystuje formatowanie uwzględniające ustawienia regionalne. `ext-openssl` również jest opcjonalne: szyfrowanie AES-CBC, AES-CTR i AES-GCM w `crypto.subtle` wymaga go, natomiast skróty i HMAC działają bez niego.

Bez `exec`, bez FFI, bez Node.js, bez własnego rozszerzenia natywnego.

## Uruchamianie skryptu z poziomu 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 wypisuje to, co skrypt zapisuje za pomocą `console.log`; nie wypisuje wartości ostatniego wyrażenia.

Zobacz [CLI dokumentację](https://phasis.inline0.dev/pl/docs/cli), aby poznać pełny zestaw poleceń.

## Osadzanie w 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
```

Instancja `Engine` zachowuje swój globalny stan między wywołaniami, więc kolejne wywołania `eval()` widzą wszystko, co zdefiniowano wcześniej.

`console.log` i jego odpowiedniki dopisują dane do bufora w silniku zamiast zapisywać je na stdout. Odczytaj go za pomocą `getConsoleOutput()` (jeden ciąg, wiersze połączone przez `\n`) lub `getConsoleLines()` (lista wierszy), a następnie wyczyść za pomocą `clearConsole()`.

Szybki start: początkowo instalowany jest tylko rdzeń niezbędny do załadowania specyfikacji (`Object`, `Function`, `Array`, `Promise`, `Symbol`, `BigInt`, `RegExp` oraz typy błędów). `Map`, `TypedArray`, `Temporal`, `Intl`, `URL`, `fetch`, pełne pakiety Web Platform / Fetch i cała reszta są przejrzyście doładowywane przy pierwszym odczycie. Przekaż `new Engine(eager: true)`, aby zainstalować wszystkie wbudowane elementy podczas tworzenia instancji — przydatne w narzędziach zgodności, które sprawdzają deskryptory przed ich odczytem; rzadko potrzebne przy zwykłym osadzaniu.

## Wywoływanie funkcji JS z PHP

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

`call()` wyszukuje funkcję według nazwy w obiekcie globalnym i wywołuje ją z przekazanymi argumentami PHP (automatycznie konwertowanymi na wartości JS).

## Udostępnianie funkcji wywoływalnej PHP jako funkcji 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")');
```

Domknięcia PHP są opakowywane jako funkcje JS. Ich argumenty podczas wywołania są konwertowane z JS na PHP, a wartości zwracane są konwertowane z powrotem z PHP na JS.

## Obiekty PHP

Obiektów PHP nie można jeszcze współdzielić z JavaScript. `setGlobal()` z prostym obiektem PHP wiąże `undefined` (śledzone w [zgłoszeniu #18](https://github.com/inline0/phasis/issues/18)). Przekazuj dane jako tablice, które są kopiowane do JS, a zachowanie udostępniaj jako domknięcia:

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

Szczegóły i inne obejścia znajdziesz w sekcji [Współdzielone obiekty](https://phasis.inline0.dev/pl/docs/interop/shared-objects).

## Limity zasobów

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

`maxLoopIterations` (domyślnie 100,000) to jedyny limit, który można dostosować w czasie działania; obecnie dotyczy wyłącznie kodu uruchamianego przez interpreter przechodzący po drzewie. Pętle uruchamiane przez maszynę wirtualną kodu bajtowego (ciała funkcji i większość kodu najwyższego poziomu) nie są zliczane, więc sam limit nie zatrzymuje `while (true) {}` ([zgłoszeniu #19](https://github.com/inline0/phasis/issues/19)). Gdy limit zostanie osiągnięty, błąd można przechwycić w JS; jeśli nie zostanie przechwycony, trafia do PHP jako `Phasis\Exceptions\InternalError`, podklasa `Phasis\Exceptions\RuntimeError`.

Silnik ma również stały limit stosu wywołań wynoszący 4,096 ramek (oraz zabezpieczenie dla transpilorowanych domknięć ograniczone do 8,192 ramek); jego przekroczenie powoduje błąd „Maximum call stack size exceeded”, ponownie jako `InternalError`. Nie ma limitu czasu rzeczywistego, dlatego nieufny kod uruchamiaj pod kontrolą własnego `max_execution_time` PHP lub w osobnym procesie. Zobacz [API: setLimit](https://phasis.inline0.dev/pl/docs/api#setlimit).

## Następne kroki

- [API dokumentacja](https://phasis.inline0.dev/pl/docs/api) — pełny zakres `Phasis\Engine`.
- [Współdziałanie](https://phasis.inline0.dev/pl/docs/interop) — reguły konwersji wartości, funkcje hosta, obiekty PHP.
- [Zgodność](https://phasis.inline0.dev/pl/docs/compatibility) — zaimplementowane funkcje, pokrycie test262.
- [Parser](https://phasis.inline0.dev/pl/docs/parser) i [Formater](https://phasis.inline0.dev/pl/docs/formatter) — parsowanie i formatowanie JavaScript bez jego wykonywania.
- [Zaawansowane](https://phasis.inline0.dev/pl/docs/advanced) — architektura, maszyna wirtualna kodu bajtowego, testy wydajności i testowanie z użyciem wzorca.
