This may be my last WordPress-related post until I’m back from my Sabbatical on September 26th. Enjoy!
WebAssembly is easier than you think. It is difficult to get started with, but then it’s not. I’ve spent the last 10 months learning that, and now I will save you that time by sharing how to build PHP into WebAssembly in 10 minutes.
And if you’ve never heard of WebAssembly, you can catch up here. Tl;dr it’s kinda a way of running regular desktop programs in the browser.
Building “Hello World” to WebAssembly is easy
Here’s a simple C program we’re going to build:
#include <stdio.h>
int main() {
printf ("Hello, World!\n");
return 0;
}
Normally, we’d use a compiler called cc from GNU build tools to build this program. It would produce an executable file called hello
:
$ cc main.c -o hello
$ ls
hello main.c
$ ./hello
Hello, World!
For WebAssembly, we’ll use a compiler called emcc from Emscripten build tools to build our program. It produces an “executable” WebAssembly file called hello.wasm
and a JavaScript bindings file called hello.js
:
$ emcc ./main.c -o hello.js
$ ls
hello.js hello.wasm main.c
$ node hello.js
Hello, World!
And since it’s just JavaScript, we can use it in the browser:
<!DOCTYPE html>
<script src="hello.js"></script>

And, on an abstract level, that’s it!
Building PHP to WebAssembly is only slightly harder
PHP interpreter may be more complex than Hello World, but ultimately it is still a C program, and we can use the same technique to build it as WebAssembly! For simplicity, we’ll focus on the CLI version of PHP.
First, we need to grab the source:
$ git clone https://github.com/php/php-src.git php-src --branch PHP-8.0 --single-branch --depth 1
Typically, PHP is built as a native executable with GNU build tools:
$ cd php-src
$ ./buildconf --force
$ ./configure --disable-all --enable-cli --enable-cgi
$ make -j8
And then it’s used in the CLI like any other terminal tool:
$ /root/build/php -v
PHP 8.0.27-dev (cli) (built: Jul 3 2023 10:10:13) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.27-dev, Copyright (c) Zend Technologies
Building PHP as a WebAssembly module is similar, except it involves Emscripten build tools like emconfigure
and emmake
:
$ ./buildconf --force
$ emconfigure ./configure --disable-all --enable-cli --enable-cgi --without-pcre-jit
$ EMCC_CFLAGS='-sERROR_ON_UNDEFINED_SYMBOLS=0 -sEXPORT_NAME="PHP"' emmake make -j8
And that’s it!
We’ve added a few extra options to:
- Disable PCRE JIT – it’s unsupported by Emscripten
- Turn the
undefined symbol: getdtablesize
compilation error into a warning - Use
PHP
JavaScript variable as a source of startup options
But other than that, we followed the same process as for a native build.
We can now run the built php
file. It may have no extension but it’s a JavaScript file and runs on Node.js:
$ node /root/php-src/sapi/cli/php -v
munmap() failed: [28] Invalid argument
PHP 8.0.27-dev (cli) (built: Jul 3 2023 10:23:54) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.27-dev, Copyright (c) Zend Technologies
It worked, yay!
And since it’s just JavaScript, we can also use it in the browser (via http://
):
<!DOCTYPE html>
<script>
window.PHP = {
arguments: ['-v']
}
</script>
<script type="text/javascript" src="php.js"></script>

And if you wonder what’s up with the munmap
warning – I’m not actually sure, but it can be silenced by adding #define ZEND_MM_ERROR 0
to php-src/main/php_config.h
after ./configure
and before make
.
And that’s how you run PHP as WebAssembly. Yay!
If you’d like to play with it, here’s a convenient Dockerfile for you, and if you want to learn more, MDN is a great starting point.
Limitations and a way around them
There are a few important limitations to keep in mind. First, this is just the CLI version. Second, it has no access to your files or network since WebAssembly modules are isolated from their environment. Effectively, our WebAssembly module is not ready to serve HTTP requests as it is.
I’ve spent a lot of time solving these problems so that you don’t have to. WordPress Playground ships PHP in the @php-wasm/node and @php-wasm/web npm packages. The documentation is a work in progress, but check them out – you may find them quite useful!
Leave a Reply