elephc turns a subset of PHP into native binaries with a Rust compiler
A PHP-to-native compiler. Takes a subset of PHP - including eval() - and compiles it directly to native assembly, producing standalone binaries for macOS ARM64, Linux ARM64, and Linux x86_64. No VM, no external runtime, no dependencies: dynamic eval falls back to an optional statically linked interpreter.
At a glance
- What is it?
- elephc is a MIT licensed, ahead-of-time PHP to native compiler written in Rust, producing standalone executables for macOS ARM64, Linux ARM64 and Linux x86_64, with a macOS host also cross-compiling for iOS. Ordinary code is compiled straight to assembly with no opcode fallback, while eval() falls back to an optional statically linked interpreter. The last push was on 2026-10-22 and nightly builds ship almost daily.
- Who is it for?
- Adopt elephc if you maintain PHP code and want a single native binary with no PHP runtime, and you are willing to restrict yourself to the documented subset of the language and to the compiler extensions rather than the full PHP surface.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Ordinary PHP is compiled straight to assembly with no opcode fallback
elephc is a compiler, not a bundler or a transpiler. The description in the repository is a PHP-to-native compiler that takes a subset of PHP and compiles it directly to native assembly, and the README stresses the point: there is no VM, no external runtime and no dependencies in the resulting binary. The badge line in the README makes the same claim in shorthand, with no Zend Engine and no external PHP runtime.
What the README calls ahead-of-time compilation is the ordinary path. Source is compiled to native code with no opcode fallback, so the produced executable contains machine code rather than a bundled interpreter and a bytecode file. The compiler is written in Rust, and the workspace structure reflects a serious codebase rather than a weekend project: separate crates for TLS, PDO with SQLite and PostgreSQL, cryptography, arbitrary precision decimal math, character set conversion, multibyte encoding, phar archive reads, timezone introspection, image handling, a prefork web server, process control and curl.
The language surface is broad in the ways that matter for ordinary application code. The README lists classes with single inheritance, interfaces, instanceof, nullsafe access, abstract and final classes, typed and static properties, constructor property promotion, traits, case-insensitive symbol lookup for functions, classes and methods, self, parent and static with late static binding, readonly properties and classes, enums, attributes on declarations, named arguments, first class callables, typed parameters and returns, try, catch, finally and throw, visibility modifiers, union and nullable types, and copy-on-write arrays.
That is a substantial subset, and the qualifier in the repository description still matters: it is a subset, and the documentation rather than the compiler will tell you where the edges are.
Five targets across desktop, server and iOS
The output matrix is stated plainly in the README. Standalone executables and compiler release archives target macOS ARM64, Linux ARM64 and Linux x86_64, and a macOS host also cross-compiles libraries for iOS ARM64 devices and for the iOS ARM64 Simulator. That is the five compile targets the README counts, and the split matters for what you can build where: an iOS library can only be produced from a macOS host, so a Linux build server cannot produce it.
Release packaging is described as three release hosts with five targets, and the release naming in the repository tags follows a nightly pattern. The recent tags include nightly-20261019 and nightly-20261018, carrying version strings of the form 0.27.3-nightly.20261019+g955f7df6c, where the trailing part is a commit identifier.
That naming has a practical consequence for how you consume the project. There is no long-term support release or a stable channel listed, and the Cargo manifest version is 0.27.3. A team that needs a pinned compiler for reproducible builds has to pin a nightly tag or a commit explicitly, because the nightly channel moves every day and the version number alone will not identify a build.
The upstream project also points at its own website, elephc.dev, and the README describes the toolchain as built and maintained independently.
eval() is the one construct that can pull in an interpreter
Dynamic evaluation is the hard case for any ahead-of-time PHP compiler, and elephc handles it by not pretending the problem does not exist. Ordinary source is compiled ahead of time, while experimental eval() can embed an optional interpreter bridge when runtime parsing is required. The repository description frames it the same way, saying that dynamic eval falls back to an optional statically linked interpreter.
The Cargo workspace shows where that bridge lives. One of the static libraries built as a default workspace member is the Magician interpreter, described in the manifest as the optional eval runtime, and the manifest comments explain that these bridges are built into the target profile directory, where the linker locates them for programs that use those features.
Two implications follow. First, a program that calls eval() at runtime needs that interpreter linked in, so the output is no longer a purely compiled binary in the strict sense. Second, the README labels the eval path as experimental, which is the sort of word worth taking literally before you depend on it. The costs of the bridge also appear in the manifest comments, which go out of their way to note that the curl bridge declares extern C symbols without linking them, so that a plain cargo build or cargo test never requires a system libcurl. That level of care about not dragging in a system library is a good sign about the build hygiene, and it is also a hint that the feature matrix around the optional bridges is genuinely conditional.
packed class, buffer, ptr and extern extend the language
The README explains that PHP has limits for performance-critical and systems-level work, and that elephc answers that with compiler extensions rather than by asking developers to switch languages. The named constructs are packed class for flat POD records, buffer<T> for contiguous typed arrays, ptr for raw memory access, and extern for FFI.
Each one addresses a specific gap. A packed class gives you a record laid out flat in memory, which is what you want when the data is a plain set of fields rather than an object graph. buffer<T> gives a typed contiguous array, so the element type is part of the type rather than a property of the values at runtime. ptr grants raw memory access, and extern opens the door to foreign functions through the FFI mechanism.
The HTTP server demo shows what these buy. It is described as an asynchronous HTTP/1.1 server built entirely in PHP and compiled to a single native binary, using a non-blocking poll() event loop, one Fiber per connection, raw TCP sockets through extern FFI, plus an HTTP parser and a router, with no interpreter, no PHP-FPM and no Nginx in the path. Raw TCP sockets through extern FFI is exactly the case that plain PHP cannot express.
The second demo is a DOOM renderer that loads original WAD files and renders a level entirely in PHP compiled to native code, with BSP traversal, perspective projection, per-column fog, sector lighting, collision detection and step climbing all in the PHP source.
One caveat about the FFI route: a bridge to a C library still needs that library at link time on the target, which is why the manifest goes to such lengths over the curl dependency. FFI moves the dependency question, it does not answer it.
The two demo programs are the argument for the project
The README devotes its two largest sections to the HTTP server and the DOOM renderer, and the reason is that they are the evidence a compiler project needs. A claim that PHP can compile to native code is easy to make and hard to believe, so the project ships complete programs rather than snippets. Each demo directory is described as containing the full source and build instructions, so the examples are reproducible rather than promotional.
The DOOM renderer is described as the flagship example, and its detail level is what makes it credible: a real-time 3D renderer loading original DOOM WAD files and rendering E1M1, with the graphics pipeline described in terms of BSP traversal, perspective projection, per-column fog and sector lighting, plus collision detection and step climbing. None of that is reachable from a language that has no typed memory access.
The examples directory follows the same principle at smaller scale. It holds many separate directories, one per language feature or behaviour, among them abstract-properties, advanced-functions, anonymous-classes, append-log, arithmetic, array-access-exception-order, array-internal-pointer, array-parity, arrays, assoc-arrays, asymmetric-visibility, attributes, autoload-reflection-stress, bcmath, binary-literals, bitwise, calendar, callbacks, case-insensitive-symbols, catchable-access-errors, cdylib, classes, cli-args and closures, along with a build-all.sh script.
Those directory names read like a conformance suite, and that is how they should be read. A language subset is only credible when there is a per-feature test corpus, and the layout suggests the compiler is developed against exactly that.
Building the compiler means building a workspace of static libraries
The repository is a Cargo workspace whose root package is the compiler itself:
[package]
name = "elephc"
version = "0.27.3"
edition = "2021"
default-run = "elephc"
description = "A PHP-to-native AOT compiler"
license = "MIT"The default-run setting matters when you build from source, since it tells Cargo which binary to run when the package is invoked without a target name. The workspace members are the root package plus the contract crates and the static library crates described above, and the manifest comments explain that the bridge static libraries are default members so that a plain cargo build or cargo test produces them in the target directory for the linker to find.
The documentation for building the two demos is in the demo directories themselves, and the repository also ships test Dockerfiles for Linux ARM64 and Linux x86_64, which is a reasonable way to reproduce the build matrix without owning the machines. There is a Dockerfile.test-linux-arm64 and a Dockerfile.test-linux-x86_64 at the top level, alongside scripts/, tools/, docs/, examples/, benchmark/ and a build.rs at the root.
The README also describes the project's internal philosophy in a way that matters to anyone reading the source. The author says the project was made as modular as possible, that every function has its own codegen file, and that each one is commented line by line so a reader can see how a high-level construct becomes its low-level equivalent. That is a deliberate design choice for a compiler people are meant to study, and it is why the crate layout is as granular as it is.
The benchmarks compare against C and PHP, and they run on shared runners
Continuous integration measures native execution against equivalent C and PHP fixtures, along with Magician eval and buffer and array workloads, and the README is clear that times exclude compilation and linking. The nightly statistics workflow keeps histories and graphs current, and the benchmark directory holds every suite, generated reports, the measurement methodology and an interactive dashboard.
The honesty in the last sentence is the part to hold onto: shared CI runner timings are useful for trends, and that is what they are. Numbers produced on shared runners vary with what else the machine is doing, so the medians and trend lines are the usable output rather than any single absolute figure. The README presents them as an image of native execution medians and recent trends rather than as a headline number.
The limits of the project are easier to state than the measurements. It compiles a subset of PHP, so code using features outside the documented surface needs checking against the docs directory. eval() is described as experimental and adds an interpreter bridge. The extension story depends on the crates in the workspace, and a system library needed by an extern bridge has to be present on the target. None of that makes the project unusable; it defines the envelope.
For maintenance and licensing, the repository is not archived and the last push was on 2026-10-22, with nightly releases dated 2026-10-19 and 2026-10-18. The licence is MIT, so the code can be used, modified and redistributed with the notice retained, and that is a description of the terms rather than legal advice.
Editorial conclusion
Adopt elephc if you maintain PHP code and want a single native binary with no PHP runtime, and you are willing to restrict yourself to the documented subset of the language and to the compiler extensions rather than the full PHP surface. Do not adopt it for an existing application that relies on eval-heavy or dynamically generated code, on extensions outside the crates the workspace provides, or if you need a release channel other than nightlies with version numbers in the 0.27 range. Verify first by compiling one small file from the examples directory on your target triple and reading the generated assembly for the constructs you actually use.
Frequently asked questions
What is elephc and what does it produce?
elephc is a PHP-to-native ahead-of-time compiler written in Rust that takes a subset of PHP and compiles it directly to native assembly, producing standalone binaries with no virtual machine, no external runtime and no dependencies. The README counts five compile targets: macOS ARM64, Linux ARM64, Linux x86_64, plus iOS ARM64 and the iOS ARM64 Simulator cross-compiled from a macOS host.
How does elephc handle eval()?
Ordinary source is compiled ahead of time with no opcode fallback, while experimental eval() can embed an optional statically linked interpreter bridge when runtime parsing is required. That bridge is the Magician runtime, one of the static libraries built as a default workspace member.
What are the packed class, buffer, ptr and extern constructs in elephc?
They are compiler extensions described in the README: packed class for flat POD records, buffer<T> for contiguous typed arrays, ptr for raw memory access, and extern for FFI. They exist so that systems-level work can be done in PHP, for example the HTTP server demo that opens raw TCP sockets through extern FFI.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/illegalstudio-elephc)Was this useful?