DEV Community

Cover image for Web Developer = Embedded Developer: Real PHP Now Runs on the ESP32 (v1.0.0)
Gianfrancesco
Gianfrancesco

Posted on

Web Developer = Embedded Developer: Real PHP Now Runs on the ESP32 (v1.0.0)

If you can write index.php, you can already program a microcontroller. That's not a metaphor.

PHP on ESP32 just hit 1.0.0 — the first official release. It takes the real PHP interpreter, the unmodified Zend engine straight from php.net, cross-compiles it for a chip that costs about $4, and runs your PHP on the bare board. No operating system underneath. No transpiler. No "PHP-like" language subset. The same index.php, the same opcodes, the same array_map and preg_match and json_encode — because it is literally the same C code, built for the chip's own CPU.

Hand the same script to this engine or to a desktop php and you get the same output.


Wait — real PHP? On a microcontroller?

Yes. The whole engine is compiled in: the lexer, the parser, the opcode compiler, the VM and executor, the garbage collector, the object/class/exception model. <?php echo 1 + 1; travels the exact same path here as on a server — source → tokens → AST → opcodes → execution.

It runs as native code, not under emulation. PHP's C is built with the chip's own cross-compiler (riscv32-esp-elf for the ESP32-P4, xtensa-esp32s3-elf for the ESP32-S3), and the opcodes execute on the board's CPU. The integration point is the official embed SAPI — the same interface any C program uses to host PHP.

The standard library comes with it: ext/standard, PCRE, JSON, hashing, SPL, reflection, the CSPRNG. Optional extensions layer on per project.

Captured on an ESP32-S3-Zero "Super Mini" (Quad 2MB PSRAM @ 80MHz, CPU 160MHz), PHP 8.4.25, no
opcache, with the native_gpio C extension compiled in. See README.md for the S3 / P4 comparison.

... (boot log) ...
I (562) esp_psram: Found 2MB PSRAM device
I (562) esp_psram: Speed: 80MHz
I (802) cpu_start: cpu freq: 160000000 Hz
I (805) esp_psram: Adding pool of 2048K of PSRAM memory to heap allocator
...

==== php-baremetal benchmark ====
PHP 8.4.25
(PSRAM size/speed and CPU freq are in the boot log above)

PSRAM: 744.7 KB free of 2,048.0 KB   |   internal RAM: 183.4 KB free of 326.4 KB

compiled footprint (PSRAM consumed to compile a source file):
  file              lines    source   compiled
  bench_small.php      17    0.4 KB     2.3 KB
  bench_medium.php     76    2.0 KB    10.3 KB
  bench_large.php     167    4.2 KB    22.4 KB

GPIO tight loop (100000 writes on GPIO 2):
  PHP loop:     3229 ns/write  ->  309,687 writes/s  ~154,843 Hz  (empty loop 829 ns)
  native C:     357 ns/write  ->  2,804,239 writes/s  ~1,402,119 Hz  (9x faster than PHP)

execution: 1,090-row working set = 403.1 KB in PSRAM (710.1 KB was free)

==== done ====
Enter fullscreen mode Exit fullscreen mode

Here's the "hello world" of embedded — blinking an LED — written entirely in PHP. setup() runs once, then loop($tick) is called forever (Arduino-style; the loop lives in C so the watchdog stays happy):

<?php
// index.php: blink an LED on GPIO2.
define('LED', 2);

function setup(): void {
    gpio_mode(LED, GPIO_OUTPUT);
    echo 'PHP ' . PHP_VERSION . " up\n";
}

function loop(int $tick): void {
    gpio_write(LED, $tick % 2);   // on for odd ticks, off for even
    delay(500);                    // milliseconds
}
Enter fullscreen mode Exit fullscreen mode

gpio_mode, gpio_write, gpio_read and delay come from a small built-in extension. echo goes to the serial console. That's it — three lines of PHP driving a physical pin.

Led blink on esp32-p4

Your framework, browsable, on the chip

On a board with networking, the firmware can run an HTTP server and hand each request to a fresh PHP run — the way a script runs behind Apache or PHP-FPM. $_SERVER, $_GET, $_POST, cookies and sessions are populated per request. Whatever your script prints becomes the response body.

That's enough to make a framework browsable: on the ESP32-P4 (32 MB PSRAM), stock Laravel and Symfony both serve pages this way. Not a fork, not a cut-down build — the real thing.

And because every ESP32-S3 has WiFi on the die, a board can create its own network and serve a page over it — no router, no cable. One of the examples, wifi-ap-s3-rgb-manage, boots a WiFi access point and serves a live PHP page that controls the board's onboard RGB LED from your phone.

Here's what happens end to end, and every piece of it is PHP. A one-time init script runs once at boot, before the server starts: it brings up a WiFi access point — SSID, password, 192.168.4.1 — and initializes the onboard RGB LED. Then the HTTP server takes over, and every request runs index.php fresh: it reads the color from $_GET/$_POST, drives the RGB LED (HSV), and prints the page back. So you connect your phone to the board's own WiFi, open the IP, move a slider — and the physical LED on the chip changes color. No cloud, no MQTT broker, no companion app: the microcontroller is the web server, and the whole thing — network, page, and pin — is a couple of .php files.

What actually runs on it

The standard library is always on. Everything else is opt-in per project:

  • Language. Classes, closures, generators, exceptions, traits, namespaces, typed properties, enums, attributes — all present, because they are the engine.
  • Text & data. ctype, mbstring (optional oniguruma), filter, tokenizer, and PDO SQLite for an on-card or in-memory database.
  • State. session on the web-server model; a reboot-persistent key-value store (store_*, backed by the chip's NVS) for values that survive a reset; and a volatile in-RAM twin (mem_*).
  • Config. A project .env is baked into the firmware and read as $_ENV / getenv().
  • OPcache. The bundled Zend OPcache is ported (no JIT, static) — caches bytecode to the card or into PSRAM so a request stops recompiling the framework every time.
  • TLS. The openssl extension has two builds — a compact mbedTLS-backed one, and full OpenSSL 3.0 (RSA, EC, X.509) — driving an HTTPS client on a networked board.

The hardware

Two things decide whether a chip qualifies: external PSRAM (the runtime heap is measured in megabytes) and ≥ 8 MB flash (the firmware image is ~3 MB). Core architecture doesn't matter — the portable VM builds on both Xtensa and RISC-V.

Family Core PSRAM Networking
ESP32-P4 dual-core RISC-V, up to 400 MHz up to 32 MB Ethernet (P4-ETH), WiFi 6 via on-board C6 companion (P4-WiFi-C6)
ESP32-S3 dual-core Xtensa LX7, 240 MHz 8 MB Ethernet (S3-ETH), WiFi on every S3

PHP 8.3.33, 8.4.25 and 8.5.10 all build today, selectable per project.

And the price tag is the fun part: an entry ESP32-S3 board with PSRAM runs the whole thing for around $4. A full PHP interpreter, on a chip that costs less than your coffee.

Try it in five commands

The supported path is phpflash, a single-binary CLI that scaffolds a project, drives the build, flashes the board and opens the serial console:

phpflash system-setup        # once: installs ESP-IDF + the firmware sources
phpflash init my-project      # scaffold (asks for board, storage, extensions)
cd my-project
$EDITOR project-src/index.php # write your PHP
phpflash flash                # build + flash the connected board
Enter fullscreen mode Exit fullscreen mode

Change the script, reset, and the board runs the new one. That's the whole loop.


So… are you an embedded developer now?

If you've shipped a PHP app, you already know the language, the standard library, the mental model. 1.0.0 means that skill set now reaches down to the metal — a real interpreter, running your real code, on a chip you can hold in your hand. Real PHP, bare metal, about four bucks.

It began as a holiday side-project. It's now a stable, documented 1.0.0 with a public roadmap — and new contributors are very welcome.

An honest word on where it stands

1.0.0 is a milestone, not a finish line. Right now this is firmly for hobbyists and tinkerers — it's a genuinely fun way to reuse your PHP skills on hardware, but it is not (yet) something I'd put in production. A lot is still missing or rough: proper multi-core handling, an I²C bus with real sensor/display drivers, an event-driven execution model, and plenty more.

The good news: that's exactly what 2.0.0 is about, and it's already in progress — dual-core done right, the I²C stack, event-driven mode, touch and IMU boards. If any of that sounds like your kind of thing, the roadmap is public and the door is open.

Links

If real PHP running bare-metal on a microcontroller made you raise an eyebrow, a ⭐ on the repo helps more people find it. What would you build with it?

Top comments (0)