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
This package is auto-updated.
Last update: 2026-09-07 23:22:02 UTC
README
The PHP builder for Elephentity.
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.0","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
composer require --dev elephentity/codegen-php
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 value objects in src/Ir
are a copy, and the runtime classes generated code refers to are strings in
src/Runtime.php 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
There is no local PHP; everything runs in a container:
./tools/php composer ci # style, static analysis, tests
./tools/php vendor/bin/phpunit --filter GoldenTest
PHPStan runs at level max with no baseline exclusions.
The golden fixtures
tests/fixtures/golden/*/ holds a committed request and the exact response it produces.
They are the specification of this program in the only form another implementation can
consume: when this is rewritten in Rust, the fixtures do not change and the new binary
has to reproduce them byte for byte.
When a deliberate change moves them, regenerate and read the diff — it is the clearest description available of what the change did to every project's generated tree.