
# Erste Schritte

## Installation

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

Phasis benötigt PHP 8.2 oder höher sowie drei Erweiterungen, die alle von `composer.json` benötigt werden:

- `mbstring` — String-Verarbeitung.
- `bcmath` — BigInt-Arithmetik und präzise Verarbeitung von Ganzzahlen.
- `curl` — der Standardtransport hinter `fetch()`.

`mbstring` und `curl` sind in den meisten Builds aktiviert. `bcmath` ist es oft nicht: In den offiziellen `php`-Docker-Images (`php:8.x-cli`, `php:8.x-fpm`) fehlt es, und manche Distributionen stellen es separat bereit (`php-bcmath`). Ohne die Erweiterung verweigert Composer die Installation von Phasis. Füge in einem Dockerfile auf Basis des offiziellen Images Folgendes hinzu:

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

Führe `php -m` aus, um zu sehen, welche Erweiterungen dein Build enthält.

`ext-intl` ist optional. Phasis funktioniert auch ohne die Erweiterung, aber die gesamte `Intl.*`-Familie (`Collator`, `NumberFormat`, `DateTimeFormat`, `PluralRules`, `Locale`, `DisplayNames`, `ListFormat`, `RelativeTimeFormat`, `Segmenter`, `DurationFormat`) sowie die nicht-ISO-Temporal-Kalender (`hebrew`, `islamic`, `japanese`, `persian` usw.) benötigen sie. Installiere sie, wenn die Host-Anwendung JS bereitstellt, das lokalisierungsabhängige Formatierung verwendet. `ext-openssl` ist ebenfalls optional: Für `crypto.subtle`-Verschlüsselung mit AES-CBC, AES-CTR und AES-GCM wird sie benötigt, Digests und HMAC funktionieren auch ohne sie.

Kein `exec`, kein FFI, kein Node.js, keine benutzerdefinierte native Erweiterung.

## Skript über die CLI ausführen

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

Die CLI gibt aus, was das Skript mit `console.log` schreibt; den Wert des letzten Ausdrucks gibt sie nicht aus.

Siehe die [CLI Referenz](https://phasis.inline0.dev/de/docs/cli) für den vollständigen Befehlssatz.

## In PHP einbetten

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

Die `Engine`-Instanz behält ihren globalen Zustand zwischen Aufrufen bei, sodass nachfolgende Aufrufe von `eval()` alles sehen, was du zuvor definiert hast.

`console.log` und seine Varianten hängen Ausgaben an einen Puffer der Engine an, statt sie nach stdout zu schreiben. Lies ihn mit `getConsoleOutput()` (ein String, Zeilen verbunden mit `\n`) oder `getConsoleLines()` (eine Liste von Zeilen) aus und leere ihn mit `clearConsole()`.

Der Kaltstart ist günstig: Zunächst wird nur der Kern installiert, der die Spezifikation lädt (`Object`, `Function`, `Array`, `Promise`, `Symbol`, `BigInt`, `RegExp` und die Fehlertypen). `Map`, `TypedArray`, `Temporal`, `Intl`, `URL`, `fetch`, die vollständigen Web Platform- und Fetch-Packs sowie alles Weitere werden beim ersten Lesen transparent geladen. Übergib `new Engine(eager: true)`, um bei der Erstellung alle integrierten Komponenten zu installieren – nützlich für Konformitätstools, die Deskriptoren prüfen, bevor sie sie lesen; beim normalen Einbetten selten nötig.

## JS-Funktionen aus PHP aufrufen

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

`call()` sucht das globale Objekt anhand des Namens nach der Funktion und ruft sie mit den übergebenen Argumenten PHP auf (automatisch in JS-Werte konvertiert).

## Einen aufrufbaren Wert aus PHP als JS-Funktion bereitstellen

```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-Closures werden als JS-Funktionen verpackt. Ihre Argumente werden beim Aufruf von JS in PHP konvertiert, und ihre Rückgabewerte werden von PHP zurück in JS konvertiert.

## PHP-Objekte

PHP-Objekte können noch nicht mit JavaScript geteilt werden. `setGlobal()` mit einem einfachen PHP-Objekt bindet `undefined` (verfolgt in [Issue #18](https://github.com/inline0/phasis/issues/18)). Übergib Daten als Arrays, die nach JS kopiert werden, und stelle Verhalten als Closures bereit:

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

Weitere Details und Umgehungsmöglichkeiten findest du unter [Gemeinsam genutzte Objekte](https://phasis.inline0.dev/de/docs/interop/shared-objects).

## Ressourcenlimits

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

`maxLoopIterations` (Standardwert: 100,000) ist die einzige zur Laufzeit anpassbare Grenze und gilt derzeit nur für Code, den der baumwandelnde Interpreter ausführt. Schleifen der Bytecode-VM (Funktionskörper und der Großteil des Codes auf oberster Ebene) werden nicht gezählt, daher verhindert eine Begrenzung allein `while (true) {}` nicht ([Issue #19](https://github.com/inline0/phasis/issues/19)). Wird die Grenze erreicht, kann der Fehler in JS abgefangen werden; bleibt er unbehandelt, erreicht er PHP als `Phasis\Exceptions\InternalError`, einer Unterklasse von `Phasis\Exceptions\RuntimeError`.

Die Engine hat außerdem eine feste Obergrenze von 4,096 Frames für den Aufrufstack (und eine Schutzgrenze von 8,192 Frames für transpilierte Closures); bei Überschreitung wird erneut als `InternalError` der Fehler „Maximum call stack size exceeded“ ausgelöst. Es gibt keine Laufzeitbegrenzung, führe nicht vertrauenswürdigen Code daher unter PHPs eigener `max_execution_time` oder in einem separaten Prozess aus. Siehe [API: setLimit](https://phasis.inline0.dev/de/docs/api#setlimit).

## Nächste Schritte

- [API Referenz](https://phasis.inline0.dev/de/docs/api) – vollständige `Phasis\Engine`-Schnittstelle.
- [Interoperabilität](https://phasis.inline0.dev/de/docs/interop) – Regeln zur Wertkonvertierung, Host-Funktionen, PHP-Objekte.
- [Kompatibilität](https://phasis.inline0.dev/de/docs/compatibility) – implementierte Funktionen und test262-Abdeckung.
- [Parser](https://phasis.inline0.dev/de/docs/parser) und [Formatter](https://phasis.inline0.dev/de/docs/formatter) – JavaScript parsen und formatieren, ohne es auszuführen.
- [Fortgeschrittenes](https://phasis.inline0.dev/de/docs/advanced) – Architektur, Bytecode-VM, Benchmarks und Oracle-Tests.
