# php2vala Library ABI and Optimizer Notes

These notes capture current design decisions for future php2vala work in this SVN tree.

## Runtime Function Resolution

- php2vala should not require hard-coded knowledge of normal PHP function names when a runtime VAPI can describe the function.
- Prefer generic resolution through installed `valaphp-runtime-*.vapi` metadata.
- Runtime lookup must prefer exact unversioned package names such as `valaphp-runtime-embed` over stale or unrelated versioned/local VAPIs.
- Do not keep developer-local probe paths in source code. In particular, no `VALAPHPTEST` paths or `/home/peters/VALAPHPTEST` defaults belong in php2vala.

## Runtime Static Optimizer ABI

Runtime packages are the source of truth for optimizer-call availability. php2vala loads installed `.vapi` files for `valaphp-runtime-core`, `valaphp-runtime-embed`, and native `valaphp-runtime-*` packages, then chooses the best ABI by symbol name and signature.

Naming contract:

- `<php_function>_zval`: PHP-compatible dynamic ABI. Arguments and return value are `Php.zval` where PHP semantics are mixed or by-reference.
- `<php_function>_static`: typed optimizer ABI for the normal static shape of a function.
- `<php_function>_<shape>_static`: typed optimizer ABI for one specific safe shape, for example `preg_match_bool_static`, `rtrim_chars_static`, `pack_string_static`, or `sprintf_string_int_static`.

The optimizer may use a static symbol only when the generated call shape can be converted to the VAPI signature. php2vala reads runtime VAPIs dynamically, chooses a matching `*_static` or `*_<shape>_static` symbol by argument count, and emits typed conversions such as `Php.zval_to_string()`, `Php.zval_to_int()`, `Php.truthy()`, or direct `Php.zval` passthrough based on the VAPI parameter types. If no safe match exists, it falls back to the zval ABI. This keeps PHP/Vala source structure comparable while still avoiding unnecessary temporary `Php.zval` values in hot loops.

Examples:

```vala
// Runtime VAPI provides this:
public static bool preg_match_bool_static (string pattern, string value, string php_file, int php_line) throws Error;

// PHP:
$ok = preg_match($pattern, $line);

// Optimized zval context:
Php.zval.boolean (PhpEmbed.preg_match_bool_static (
    Php.zval_to_string (pattern),
    Php.zval_to_string (line),
    php_file,
    php_line
));
```

`preg_match($pattern, $line, $matches)` must still use `preg_match_zval`, because the by-reference match-array shape is not equivalent to the boolean-only static variant.

## Optimizer Stages

- `--no-optimize-local-vars`: zval-first behavior.
- `--optimize-local-vars`: per-function local static typing.
- `--optimize-file-func-vars`: whole-file local function static helpers plus zval wrappers.
- `--optimize-cross-file-func-vars`: stage 4 and the default mode for library consumers. It may use statically typed calls across files when the loaded PHP stub says a static ABI exists.

The cross-file optimizer is the default. When it is explicitly disabled or a lower optimizer stage is selected, calls loaded from PHP stubs should keep using the zval ABI.

## Library ABI

When php2vala generates library output, exported Vala symbols should be ABI-explicit:

- Static/native ABI: `<php_function_name>_static`
- zval ABI: `<php_function_name>_zval`

The plain PHP function name should remain the PHP-facing name in the generated `.php` stub, not the exported Vala symbol.

Example:

```vala
public static void print_copyright_static (...) throws Error
public static Php.zval print_copyright_zval (...) throws Error
```

The zval ABI must always remain available for compatibility. The static ABI is additional.
Even with fewer optimizer stages, library output must still export the zval entry as `<php_function_name>_zval`; it must not fall back to exporting the plain PHP name.

For unclear typing or optional arguments, prefer generating additional explicit variants rather than weakening the ABI contract silently. If a static ABI cannot be generated safely, keep the zval ABI.

## Generated PHP Stubs

Library stubs are generated by php2vala, not committed as hand-written source files.

The stub should stay PHP-readable and expose the normal PHP function name:

```php
function print_copyright ($detailed = true): void {}
```

php2vala-specific ABI metadata belongs in doc comments:

```php
/**
 * @php2vala-static print_copyright_static
 * @php2vala-static-return void
 * @php2vala-zval print_copyright_zval
 */
function print_copyright ($detailed = true): void {}
```

Consumers using `--php-stub` can then resolve:

- `--optimize-cross-file-func-vars` -> call the `@php2vala-static` symbol when available.
- Other modes -> call the `@php2vala-zval` symbol.

php2vala also auto-loads installed stubs from the standard VALAPHP data directories, for example `/usr/share/valaphp/*/*.stub.php`, so normal consumers do not need to pass every installed library stub manually.

## Meson Integration

Example libraries such as `valaphp-libpwcommon` should run php2vala once and generate all required outputs from one `custom_target()`:

- generated `.vala`
- generated `.stub.php`

Install the generated stub via Meson's normal `custom_target(install: true, install_dir: [...])` output installation. Avoid `meson.add_install_script()` or shell/install scripts for this.

## Diagnostics

Fallback diagnostics should describe the final ABI chosen, not speculative resolver steps.

Good examples:

- `using embed static fallback`
- `using embed zval fallback`

Avoid misleading messages such as `trying embed static` when the actual path is zval.
