
# Guida introduttiva

## Installazione

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

Phasis richiede PHP 8.2 o versioni successive e tre estensioni, tutte necessarie per `composer.json`:

- `mbstring` — gestione delle stringhe.
- `bcmath` — operazioni aritmetiche su BigInt e gestione dei numeri con precisione intera.
- `curl` — il trasporto predefinito usato da `fetch()`.

`mbstring` e `curl` sono abilitate nella maggior parte delle build. Spesso `bcmath` non lo è: le immagini ufficiali `php` Docker (`php:8.x-cli`, `php:8.x-fpm`) non la includono e alcune distribuzioni la forniscono separatamente (`php-bcmath`). Senza questa estensione, Composer non si installa Phasis. In un Dockerfile basato sull’immagine ufficiale, aggiungete:

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

Eseguite `php -m` per vedere quali estensioni include la vostra build.

`ext-intl` è facoltativo. Phasis funziona anche senza, ma richiedono questa estensione l’intera famiglia `Intl.*` (`Collator`, `NumberFormat`, `DateTimeFormat`, `PluralRules`, `Locale`, `DisplayNames`, `ListFormat`, `RelativeTimeFormat`, `Segmenter`, `DurationFormat`) e i calendari Temporal non ISO (`hebrew`, `islamic`, `japanese`, `persian` ecc.). Installatela se l’applicazione host espone JS che usano una formattazione basata sulle impostazioni locali. Anche `ext-openssl` è facoltativo: la crittografia AES-CBC, AES-CTR e AES-GCM di `crypto.subtle` lo richiede, mentre digest e HMAC funzionano senza.

Niente `exec`, niente FFI, niente Node.js, nessuna estensione nativa personalizzata.

## Eseguire uno script dalla riga di comando 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 stampa ciò che lo script scrive con `console.log`; non stampa il valore dell’ultima espressione.

Per l’elenco completo dei comandi, consultate la documentazione di riferimento di [CLI](https://phasis.inline0.dev/it/docs/cli).

## Incorporare in 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
```

L’istanza `Engine` mantiene lo stato globale tra una chiamata e l’altra, quindi le chiamate successive a `eval()` vedono tutto ciò che è stato definito in precedenza.

`console.log` e le funzioni correlate aggiungono i contenuti a un buffer del motore invece di scriverli su stdout. Leggeteli con `getConsoleOutput()` (un’unica stringa, con le righe unite da `\n`) o `getConsoleLines()` (un elenco di righe) e svuotate il buffer con `clearConsole()`.

L’avvio a freddo è rapido: all’inizio viene installato solo il nucleo necessario per caricare le specifiche (`Object`, `Function`, `Array`, `Promise`, `Symbol`, `BigInt`, `RegExp` e i tipi di errore). `Map`, `TypedArray`, `Temporal`, `Intl`, `URL`, `fetch`, i pacchetti Web Platform / Fetch completi e tutto il resto vengono resi disponibili in modo trasparente alla prima lettura. Passate `new Engine(eager: true)` per installare tutti i componenti integrati durante la costruzione: è utile per gli strumenti di conformità che esaminano i descrittori prima di leggerli, ma raramente serve per l’incorporamento normale.

## Chiamare funzioni JS da PHP

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

`call()` cerca la funzione per nome nell’oggetto globale e la invoca con gli argomenti PHP forniti (convertiti automaticamente in valori JS).

## Esporre una funzione richiamabile PHP come funzione 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")');
```

Le closure PHP vengono racchiuse in funzioni JS. Durante la chiamata, i loro argomenti vengono convertiti da JS a PHP e i valori restituiti vengono riconvertiti da PHP a JS.

## Oggetti PHP

Gli oggetti PHP non possono ancora essere condivisi con JavaScript. `setGlobal()` con un oggetto PHP semplice associa `undefined` (tracciato in [segnalazione n. 18](https://github.com/inline0/phasis/issues/18)). Passate i dati come array, che vengono copiati in JS, ed esponete il comportamento tramite closure:

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

Per i dettagli e altre soluzioni alternative, consultate [Oggetti condivisi](https://phasis.inline0.dev/it/docs/interop/shared-objects).

## Limiti delle risorse

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

`maxLoopIterations` (valore predefinito 100,000) è l’unico limite configurabile durante l’esecuzione e al momento si applica solo al codice eseguito dall’interprete che attraversa l’albero. I cicli eseguiti dalla VM bytecode (corpi delle funzioni e la maggior parte del codice di livello superiore) non vengono conteggiati, quindi il solo limite non arresta `while (true) {}` ([segnalazione n. 19](https://github.com/inline0/phasis/issues/19)). Quando si raggiunge il limite, l’errore può essere intercettato in JS; se non viene intercettato, arriva a PHP come `Phasis\Exceptions\InternalError`, sottoclasse di `Phasis\Exceptions\RuntimeError`.

Il motore ha anche un limite fisso di 4,096 frame per lo stack delle chiamate (e una protezione di 8,192 frame per le closure transpiled); superarlo genera «Maximum call stack size exceeded», sempre come `InternalError`. Non esiste un limite di tempo reale: eseguite il codice non attendibile con il limite `max_execution_time` di PHP o in un processo separato. Consultate [API: impostaLimite](https://phasis.inline0.dev/it/docs/api#setlimit).

## Passaggi successivi

- [API documentazione di riferimento](https://phasis.inline0.dev/it/docs/api) — superficie `Phasis\Engine` completa.
- [Interoperabilità](https://phasis.inline0.dev/it/docs/interop) — regole di conversione dei valori, funzioni host, oggetti PHP.
- [Compatibilità](https://phasis.inline0.dev/it/docs/compatibility) — funzionalità implementate, copertura test262.
- [Parser](https://phasis.inline0.dev/it/docs/parser) e [Formattatore](https://phasis.inline0.dev/it/docs/formatter) — analizzare e formattare JavaScript senza eseguirlo.
- [Avanzate](https://phasis.inline0.dev/it/docs/advanced) — architettura, VM bytecode, benchmark, test con oracle.
