elephentity / codegen-php
The PHP builder for Elephentity: compiles the IR into locked PHP. Build-time only.
Package info
github.com/hsimah-services/elephentity-codegen-php
pkg:composer/elephentity/codegen-php
Requires
- php: >=8.3
- nette/php-generator: ^4.1
- psr/container: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0 || ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v0.5.0
- v0.4.9
- v0.4.8
- v0.4.7
- v0.4.6
- v0.4.5
- v0.4.4
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4.0
- v0.3.0
- v0.2.0
- v0.1.0
- dev-rewrite/rust-codegen
- dev-docs/five-repo-topology
- dev-fix/edgeless-entity-unused-loader-property
- dev-fix/action-argument-decoding-undefined-variable
- dev-fix/write-context-action-accessor-return-type
- dev-fix/self-referential-arguments-return-type
- dev-feature/read-write-policies
This package is auto-updated.
Last update: 2026-09-17 03:38:27 UTC
README
The PHP builder for Elephentity.
Implemented in Rust. Build a checkout with cargo build --release --locked, or install
the executable on PATH with cargo install --path . --locked. The bin/eleph-gen-php
checkout launcher uses target/release/eleph-gen-php (or a debug build during development).
It never falls back to PHP. Installed Cargo binaries need neither PHP nor Cargo to run.
It reads one JSON request on stdin — the compiled spec, plus the target's configuration — and writes one JSON response on stdout: a path and a body per file. It never touches the filesystem. Signing and writing happen in elephentity-codegen, after this exits.
echo '{"elephentity":1,"irVersion":"1.1","target":"php","config":{}, "outputDirectory":"out","schema":{}}' | ./bin/eleph-gen-php
That fails on the empty schema, which is the point: it should be obvious how.
Installing it
# From this repository: cargo install --path . --locked # Or, when using the Composer distribution: composer require --dev elephentity/codegen-php cargo build --release --locked --manifest-path vendor/elephentity/codegen-php/Cargo.toml
Use "builder": "eleph-gen-php" for a Cargo installation, or the Composer
launcher as shown below. Then name it in eleph.json:
{
"targets": {
"php": {
"builder": "vendor/bin/eleph-gen-php",
"output": "generated",
"namespace": "App\\Entity",
"typeNamespace": "App\\Type"
}
}
}
namespace and typeNamespace are read and validated here, not upstream. Nothing else
in the pipeline knows what they mean.
It depends on nothing of Elephentity's
Not the compiler, not the runtime, not the orchestrator. The IR types in rust/ir.rs
are an independent copy, and the runtime classes generated code refers to are strings in
rust/runtime.rs rather than imports. That is deliberate: a builder that had to
composer require the framework would be a builder no other language could write. The
version gate is what holds the copy in step — a mismatch is a refusal, never a silent
misread.
Working on it
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test --locked
./tools/php composer ci
Rust sources live in rust/. Each builder owns its IR types and version gate; there
is no runtime dependency on the compiler or another builder. PHP in src/ and the
bin/eleph-gen-php-reference executable is retained as a migration oracle for the
existing tests. Production entrypoints run Rust only. PHPStan still checks the reference
and acceptance tests at level max.
PHP declarations use php_codegen.
The crate owns formatting; there is no compatibility printer. File names, runtime
interfaces, method behavior, and class-map structure remain compatible.
php tools/compare-rust.php compares the frozen PHP responses and additional scenarios
against the Rust binary using parsed, name-resolved PHP ASTs. This permits formatting,
quote style, and trailing-comma differences while checking executable structure.
The golden fixtures
tests/fixtures/golden/*/response.json pins the Rust output. The original PHP responses
are preserved as response.reference.json, unchanged, for the independent AST checks.
Only the formatting snapshots changed in this migration. The WordPress and WPGraphQL
builders retain their original output bytes.
Regenerate generated PHP once after upgrading, and commit the changed signed files. The signer itself is unchanged; formatting changes naturally produce new digests.