A Zig framework for building PHP extensions with PHP C API bindings.
ℹ️ Note: phpz already covers most PHP extension use cases, but the API is still evolving. Pin to a specific commit if you need stability.
- zig: 0.17.0-dev.1398+cb5635714
- php: 8.2-8.5 (NTS/ZTS) on Linux (x86_64/aarch64), macOS (x86_64/aarch64), Windows MSVC (x64)
- Modules — extension metadata, lifecycle hooks, phpinfo, INI, globals, observers, and exports.
- Stub integration — arginfo, function entries, constants, attributes, class metadata, and arginfo checks.
- Functions and methods — typed
Ctxarguments, returns, nullable values, raw zvals, and PHP argument errors. - Classes and OOP — bind Zig
extern structlifecycles to PHP objects, with class entries, methods, inheritance, interfaces, enums, exceptions, and handlers. - Runtime state — typed module globals, PHP/Zend globals, and superglobal access for NTS/ZTS builds.
- Zval and Zend APIs — zval conversions, ownership helpers, arrays, strings, objects, callables, functions, and resources.
- INI, phpinfo, and errors — typed INI values, phpinfo helpers, PHP errors, exceptions, and bailout-safe cleanup.
- Observers — function-call, error, and exception hooks for profiling and monitoring.
- Memory — PHP-backed Zig allocator with optional debug leak traces.
- Build integration — PHP C translation, extension linking, and platform-specific setup.
Generate a PHP extension skeleton:
# Generate a new PHP extension skeleton
# PHP >= 8.3:
curl -fsSL https://raw.githubusercontent.com/happystraw/phpz/dev/tools/phpz_skel.php \
| php -- --ext my_php_extension
# PHP 8.2:
curl -fsSLO https://raw.githubusercontent.com/happystraw/phpz/dev/tools/phpz_skel.php
php phpz_skel.php --ext my_php_extension
# Run tests (Optional)
cd my_php_extension
zig build run-testsFor a complete minimal project, see
examples/skeleton.
zig fetch --save git+https://github.com/happystraw/phpzA phpz extension usually contains:
build.zig.zon— declares thephpzdependencybuild.zig— initializesPhpzand callsphpz.addExtension<name>.stub.php— PHP API declarations<name>_arginfo.h— generated by PHP'sgen_stub.php<name>.h— includesphpz.hand the generated arginfo headersrc/root.zig— registers functions, classes, and the module
php /path/to/php-src/build/gen_stub.php <name>.stub.phpzig build -Dphp-include-dir="$(php-config --include-dir)"For the complete build.zig, stub.php, header, Zig module, and PHPT tests, use examples/skeleton as the reference.
Check out the examples/ directory for complete working examples.
Build-time Compile-time Runtime
────────── ──────────── ───────
stub.php Zig source
│ │
│ php-src/build/gen_stub.php │
▼ │
arginfo.h │
[ext_functions] │
[register_class_*] │
[register_{name}_symbols] │
│ │
│ translate-c (zig build) │
▼ ▼
PHP C bindings ─────────────► phpz comptime:
(php_c module) ├─ phpz.function() → zif_* export
├─ Class.method() → zim_* export
├─ phpz.Class(T) → wrapper type
└─ phpz.module() → get_module() export
│
├─── PHP loads .so
│
▼
module_startup [auto]
├─ register_{name}_symbols (constants)
├─ ini_entries
└─ user hook
└─ Class.register() (classes) [manual]
-
Build-time —
gen_stub.phpgeneratesarginfo.hfrom.stub.php, containing function metadata andregister_*symbols.translate-cconverts PHP C headers into Zig bindings. -
Compile-time —
phpz.function()exportszif_*wrappers,phpz.Class()creates wrapper types,phpz.module()exportsget_module()for the dynamic loader. -
Runtime — PHP loads
.so→get_module():What Registered by When How Functions ext_functionsModule init Auto: set in module entry struct Constants register_{name}_symbolsMINIT Auto: called by module_startup_funcClasses register_class_*MINIT Manual: Class.register()inmodule_startup_fnFunctions are resolved from the module entry when the extension loads; constants are registered during MINIT via the auto-generated
register_{name}_symbols. Classes require an explicitClass.register()call inmodule_startup_fn— this gives you control over registration order and the opportunity to configureObjectHandlersor parent classes.