
# Първи стъпки

## Инсталиране

```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` го изисква, но digest и 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/bg/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` (описано в [issue #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/bg/docs/interop/shared-objects) за подробности и други решения.

## Ограничения на ресурсите

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

`maxLoopIterations` (по подразбиране 100,000) е единственото ограничение, което може да се настройва по време на изпълнение, и засега важи само за код, изпълняван от интерпретатора, който обхожда дървото. Циклите, изпълнявани от виртуалната машина за байткод (телата на функции и повечето код на най-горно ниво), не се броят, така че само това ограничение не спира `while (true) {}` ([issue #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/bg/docs/api#setlimit).

## Следващи стъпки

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