
# Primeros pasos

## Instalación

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

Phasis requiere PHP 8.2 o posterior con tres extensiones, todas requeridas por `composer.json`:

- `mbstring` — gestión de cadenas.
- `bcmath` — aritmética BigInt y gestión de números con precisión entera.
- `curl` — el transporte predeterminado detrás de `fetch()`.

`mbstring` y `curl` están habilitadas en la mayoría de las compilaciones. `bcmath` suele faltar: las imágenes oficiales de `php` Docker (`php:8.x-cli`, `php:8.x-fpm`) no la incluyen, y algunas distribuciones la ofrecen por separado (`php-bcmath`). Sin ella, Composer no puede instalar Phasis. En un Dockerfile basado en la imagen oficial, añade:

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

Ejecuta `php -m` para ver qué extensiones incluye tu compilación.

`ext-intl` es opcional. Phasis funciona sin ella, pero toda la familia `Intl.*` (`Collator`, `NumberFormat`, `DateTimeFormat`, `PluralRules`, `Locale`, `DisplayNames`, `ListFormat`, `RelativeTimeFormat`, `Segmenter`, `DurationFormat`) y los calendarios de Temporal que no son ISO (`hebrew`, `islamic`, `japanese`, `persian`, etc.) la requieren. Instálala cuando la aplicación anfitriona ofrezca JS que utilicen formato sensible a la configuración regional. `ext-openssl` también es opcional: la necesitan `crypto.subtle` cifrado AES-CBC, AES-CTR y AES-GCM; los resúmenes y HMAC funcionan sin ella.

Sin `exec`, sin FFI, sin Node.js y sin extensiones nativas personalizadas.

## Ejecutar un script desde 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 imprime lo que el script escribe con `console.log`; no imprime el valor de la última expresión.

Consulta la referencia de [CLI](https://phasis.inline0.dev/es/docs/cli) para ver todos los comandos disponibles.

## Incrustar en 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
```

La instancia de `Engine` conserva su estado global entre llamadas, así que las llamadas posteriores a `eval()` ven todo lo que se haya definido antes.

`console.log` y sus funciones relacionadas añaden datos a un búfer del motor en lugar de escribir en stdout. Léelo con `getConsoleOutput()` (una cadena, con las líneas unidas por `\n`) o con `getConsoleLines()` (una lista de líneas), y vacíalo con `clearConsole()`.

El arranque en frío es rápido: al principio solo se instala el núcleo necesario para cargar la especificación (`Object`, `Function`, `Array`, `Promise`, `Symbol`, `BigInt`, `RegExp` y los tipos de error). `Map`, `TypedArray`, `Temporal`, `Intl`, `URL`, `fetch`, los paquetes completos Web Platform y Fetch, y todo lo demás se materializan de forma transparente en la primera lectura. Pasa `new Engine(eager: true)` para instalar todos los elementos integrados al construir la instancia; resulta útil en herramientas de conformidad que inspeccionan descriptores antes de leerlos y rara vez hace falta en una integración normal.

## Llamar funciones de JS desde PHP

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

`call()` busca la función por nombre en el objeto global y la invoca con los argumentos PHP proporcionados (convertidos automáticamente en valores JS).

## Exponer una función invocable de PHP como función de 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")');
```

Las clausuras de PHP se envuelven como funciones de JS. Al llamarlas, sus argumentos se convierten de JS a PHP, y sus valores de retorno se convierten de PHP a JS.

## Objetos PHP

Los objetos PHP aún no se pueden compartir con JavaScript. `setGlobal()` con un objeto PHP sencillo vincula `undefined` (seguimiento en [el problema n.º 18](https://github.com/inline0/phasis/issues/18)). Pasa los datos como matrices, que se copian en JS, y expón el comportamiento como clausuras:

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

Consulta [Objetos compartidos](https://phasis.inline0.dev/es/docs/interop/shared-objects) para ver los detalles y otras soluciones alternativas.

## Límites de recursos

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

`maxLoopIterations` (valor predeterminado 100,000) es el único límite que se puede ajustar durante la ejecución y, actualmente, solo se aplica al código ejecutado por el intérprete que recorre el árbol. No se cuentan los bucles ejecutados por la VM de bytecode (los cuerpos de funciones y la mayor parte del código de nivel superior), así que el límite por sí solo no detiene `while (true) {}` ([problema n.º 19](https://github.com/inline0/phasis/issues/19)). Al alcanzar el límite, el error se puede capturar en JS; si no se captura, llega a PHP como `Phasis\Exceptions\InternalError`, una subclase de `Phasis\Exceptions\RuntimeError`.

El motor también tiene un límite fijo de pila de llamadas de 4,096 marcos (y una protección de 8,192 marcos para clausuras transpiladas); superarlo genera el error "Maximum call stack size exceeded", también como `InternalError`. No hay límite de tiempo real, así que ejecuta el código no fiable bajo PHP, con su propio `max_execution_time`, o en un proceso separado. Consulta [API: setLimit](https://phasis.inline0.dev/es/docs/api#setlimit).

## Pasos siguientes

- [Referencia de API](https://phasis.inline0.dev/es/docs/api) — API completa de `Phasis\Engine`.
- [Interoperabilidad](https://phasis.inline0.dev/es/docs/interop) — reglas de conversión de valores, funciones del anfitrión y objetos PHP.
- [Compatibilidad](https://phasis.inline0.dev/es/docs/compatibility) — funciones implementadas y cobertura de test262.
- [Analizador](https://phasis.inline0.dev/es/docs/parser) y [Formateador](https://phasis.inline0.dev/es/docs/formatter) — analiza y formatea JavaScript sin ejecutarlo.
- [Avanzado](https://phasis.inline0.dev/es/docs/advanced) — arquitectura, VM de bytecode, pruebas de rendimiento y de referencia.
