
# Premiers pas

## Installation

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

Phasis nécessite PHP 8.2 ou une version ultérieure et trois extensions, toutes requises par `composer.json` :

- `mbstring` — gestion des chaînes.
- `bcmath` — arithmétique BigInt et gestion des nombres avec précision entière.
- `curl` — le transport par défaut derrière `fetch()`.

`mbstring` et `curl` sont activées dans la plupart des compilations. Ce n'est souvent pas le cas de `bcmath` : les images officielles `php` Docker (`php:8.x-cli`, `php:8.x-fpm`) ne l'incluent pas, et certaines distributions la fournissent séparément (`php-bcmath`). Sans elle, Composer refuse d'installer Phasis. Dans un Dockerfile basé sur l'image officielle, ajoutez :

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

Exécutez `php -m` pour voir quelles extensions sont disponibles dans votre compilation.

`ext-intl` est facultative. Phasis fonctionne sans elle, mais toute la famille `Intl.*` (`Collator`, `NumberFormat`, `DateTimeFormat`, `PluralRules`, `Locale`, `DisplayNames`, `ListFormat`, `RelativeTimeFormat`, `Segmenter`, `DurationFormat`) ainsi que les calendriers Temporal non-ISO (`hebrew`, `islamic`, `japanese`, `persian`, etc.) en ont besoin. Installez-la dès que l'application hôte expose JS qui touche au formatage tenant compte des paramètres régionaux. `ext-openssl` est également facultative : le chiffrement AES-CBC, AES-CTR et AES-GCM de `crypto.subtle` en a besoin, tandis que les condensats et HMAC fonctionnent sans elle.

Pas de `exec`, pas de FFI, pas de Node.js, pas d'extension native personnalisée.

## Exécuter un script depuis le 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
```

Le CLI affiche ce que le script écrit avec `console.log` ; il n'affiche pas la valeur de la dernière expression.

Consultez la [référence CLI](https://phasis.inline0.dev/fr/docs/cli) pour connaître toutes les commandes disponibles.

## Intégrer dans 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'instance `Engine` conserve son état global entre les appels ; les appels suivants à `eval()` voient donc tout ce que vous avez défini auparavant.

`console.log` et ses équivalents ajoutent du contenu à un tampon sur le moteur au lieu de l'écrire sur stdout. Lisez-le avec `getConsoleOutput()` (une chaîne, lignes jointes par `\n`) ou `getConsoleLines()` (une liste de lignes), et videz-le avec `clearConsole()`.

Le démarrage à froid est rapide : seul le cœur nécessaire au chargement des spécifications (`Object`, `Function`, `Array`, `Promise`, `Symbol`, `BigInt`, `RegExp` et les types d'erreur) est installé d'emblée. `Map`, `TypedArray`, `Temporal`, `Intl`, `URL`, `fetch`, les packs complets Web Platform et Fetch, ainsi que tout le reste sont chargés de façon transparente à la première lecture. Passez `new Engine(eager: true)` pour installer tous les éléments intégrés à la construction — utile pour les outils de conformité qui inspectent les descripteurs avant de les lire, rarement nécessaire pour une intégration normale.

## Appeler des fonctions JS depuis PHP

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

`call()` recherche la fonction par son nom sur l'objet global et l'appelle avec les arguments PHP fournis (convertis automatiquement en valeurs JS).

## Exposer un appelable PHP comme fonction 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")');
```

Les fermetures PHP sont enveloppées comme fonctions JS. Lors de l'appel, leurs arguments sont convertis de JS en PHP et leurs valeurs de retour sont reconverties de PHP en JS.

## Objets PHP

Les objets PHP ne peuvent pas encore être partagés avec JavaScript. `setGlobal()` avec un objet PHP simple lie `undefined` (suivi dans [l'issue #18](https://github.com/inline0/phasis/issues/18)). Transmettez les données sous forme de tableaux, qui sont copiés dans JS, et exposez le comportement sous forme de fermetures :

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

Consultez [Objets partagés](https://phasis.inline0.dev/fr/docs/interop/shared-objects) pour plus de détails et d'autres solutions de contournement.

## Limites de ressources

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

`maxLoopIterations` (100,000 par défaut) est la seule limite réglable à l'exécution ; pour l'instant, elle ne s'applique qu'au code exécuté par l'interpréteur qui parcourt l'arbre. Les boucles exécutées par la VM à bytecode (corps de fonctions et la plupart du code de premier niveau) ne sont pas comptabilisées ; cette limite seule n'arrête donc pas `while (true) {}` ([issue #19](https://github.com/inline0/phasis/issues/19)). Lorsque la limite est atteinte, l'erreur peut être interceptée dans JS ; si elle ne l'est pas, elle remonte à PHP sous la forme de `Phasis\Exceptions\InternalError`, une sous-classe de `Phasis\Exceptions\RuntimeError`.

Le moteur possède également une limite fixe de pile d'appels de 4,096 trames (et une protection à 8,192 trames pour les fermetures transpilées) ; la dépasser déclenche "Maximum call stack size exceeded", là encore sous la forme de `InternalError`. Il n'y a pas de limite de temps réel : exécutez donc le code non fiable sous le `max_execution_time` propre à PHP ou dans un processus séparé. Voir [API : setLimit](https://phasis.inline0.dev/fr/docs/api#setlimit).

## Étapes suivantes

- [Référence API](https://phasis.inline0.dev/fr/docs/api) — surface complète de `Phasis\Engine`.
- [Interopérabilité](https://phasis.inline0.dev/fr/docs/interop) — règles de conversion des valeurs, fonctions hôtes, objets PHP.
- [Compatibilité](https://phasis.inline0.dev/fr/docs/compatibility) — fonctionnalités implémentées et couverture test262.
- [Analyseur](https://phasis.inline0.dev/fr/docs/parser) et [Formateur](https://phasis.inline0.dev/fr/docs/formatter) — analyser et formater JavaScript sans l'exécuter.
- [Avancé](https://phasis.inline0.dev/fr/docs/advanced) — architecture, VM à bytecode, benchmarks et modèle de tests oracle.
