
# Початок роботи

## Встановлення

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

Для Phasis потрібен PHP версії 8.2 або новішої з трьома розширеннями, які потрібні `composer.json`:

- `mbstring` — обробка рядків.
- `bcmath` — арифметика BigInt і робота з числами з цілою точністю.
- `curl` — транспорт за замовчуванням для `fetch()`.

`mbstring` і `curl` увімкнено в більшості збірок. `bcmath` часто відсутнє: в офіційних образах `php` Docker (`php:8.x-cli`, `php:8.x-fpm`) його немає, а деякі дистрибутиви постачають його окремо (`php-bcmath`). Без нього Composer відмовляється встановлювати Phasis. У Dockerfile на основі офіційного образу додайте:

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

Запустіть `php -m`, щоб побачити, які розширення є у вашій збірці.

`ext-intl` необов’язковий. Phasis працює без нього, але вся родина `Intl.*` (`Collator`, `NumberFormat`, `DateTimeFormat`, `PluralRules`, `Locale`, `DisplayNames`, `ListFormat`, `RelativeTimeFormat`, `Segmenter`, `DurationFormat`) і календарі Temporal, що не належать до ISO (`hebrew`, `islamic`, `japanese`, `persian` тощо) потребують його. Установіть його, якщо хостова програма надає JS для форматування з урахуванням локалі. `ext-openssl` також необов’язковий: для шифрування AES-CBC, AES-CTR і AES-GCM потрібен `crypto.subtle`, але дайджести та HMAC працюють без нього.

Без `exec`, без FFI, без Node.js і без власного нативного розширення.

## Запуск скрипту з 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 виводить те, що скрипт записує через `console.log`; значення останнього виразу не виводиться.

Повний перелік команд див. у довіднику [CLI](https://phasis.inline0.dev/uk/docs/cli).

## Вбудовування в 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` зберігає глобальний стан між викликами, тому наступні виклики `eval()` бачать усе, що ви визначили раніше.

`console.log` та споріднені методи додають дані до буфера рушія замість запису в stdout. Прочитайте його через `getConsoleOutput()` (один рядок, рядки об’єднані за допомогою `\n`) або `getConsoleLines()` (список рядків), а очистіть через `clearConsole()`.

Холодний запуск швидкий: спочатку встановлюється лише ядро, потрібне для завантаження специфікації (`Object`, `Function`, `Array`, `Promise`, `Symbol`, `BigInt`, `RegExp` і типи помилок). `Map`, `TypedArray`, `Temporal`, `Intl`, `URL`, `fetch`, повні пакети Web Platform / Fetch та все інше прозоро створюються під час першого читання. Передайте `new Engine(eager: true)`, щоб під час створення встановити всі вбудовані елементи — це корисно для інструментів перевірки відповідності, які аналізують дескриптори до їх читання, але рідко потрібно для звичайного вбудовування.

## Виклик функцій JS із PHP

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

`call()` знаходить функцію за назвою в глобальному об’єкті й викликає її з переданими аргументами PHP (які автоматично перетворюються на значення JS).

## Відкриття викликуваного об’єкта PHP як функції 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")');
```

Замикання PHP обгортаються як функції JS. Під час виклику їхні аргументи перетворюються з JS на PHP, а повернуті значення — з PHP на JS.

## Об’єкти PHP

Об’єкти PHP поки що не можна спільно використовувати з JavaScript. `setGlobal()` зі звичайним об’єктом PHP прив’язує `undefined` (відстежується в [проблемі #18](https://github.com/inline0/phasis/issues/18)). Передавайте дані як масиви, які копіюються в JS, а поведінку відкривайте через замикання:

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

Докладніше про це та інші обхідні рішення див. у розділі [Спільні об’єкти](https://phasis.inline0.dev/uk/docs/interop/shared-objects).

## Обмеження ресурсів

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

`maxLoopIterations` (типове значення 100,000) — єдине обмеження, яке можна змінити під час виконання, і наразі воно стосується лише коду, який виконує інтерпретатор із обходом дерева. Цикли, що виконує віртуальна машина байткоду (тіла функцій і більшість коду верхнього рівня), не враховуються, тож саме це обмеження не зупиняє `while (true) {}` ([проблема #19](https://github.com/inline0/phasis/issues/19)). Коли межу досягнуто, помилку можна перехопити в JS; якщо її не перехопити, вона потрапить до PHP як `Phasis\Exceptions\InternalError` — підклас `Phasis\Exceptions\RuntimeError`.

Рушій також має фіксоване обмеження стека викликів у 4,096 кадрів (і захист на 8,192 кадрів для транспільованих замикань); його перевищення викликає помилку «Maximum call stack size exceeded», знову ж таки як `InternalError`. Обмеження часу виконання немає, тому запускайте недовірений код у власному `max_execution_time` для PHP або в окремому процесі. Див. [API: setLimit](https://phasis.inline0.dev/uk/docs/api#setlimit).

## Наступні кроки

- [API довідник](https://phasis.inline0.dev/uk/docs/api) — повний API `Phasis\Engine`.
- [Взаємодія](https://phasis.inline0.dev/uk/docs/interop) — правила перетворення значень, функції хоста, об’єкти PHP.
- [Сумісність](https://phasis.inline0.dev/uk/docs/compatibility) — реалізовані можливості, покриття test262.
- [Парсер](https://phasis.inline0.dev/uk/docs/parser) і [Форматувальник](https://phasis.inline0.dev/uk/docs/formatter) — розбір і форматування JavaScript без виконання коду.
- [Додаткові теми](https://phasis.inline0.dev/uk/docs/advanced) — архітектура, віртуальна машина байткоду, бенчмарки, тестування за допомогою оракула.
