Introduction: Why Does PHP Need WebAssembly?
WebAssembly (Wasm) is a low-level binary instruction format that allows executing code written in languages like C, C++, Rust, and others at near-native speed. In the context of PHP, integration with WebAssembly opens up new possibilities: from performing computationally intensive tasks on the server side to porting existing libraries without rewriting them in PHP.
PHP is a scripting language that traditionally lags behind compiled languages in performance. However, with WebAssembly you can:
- Execute speed-critical algorithms (image processing, encryption, parsing) on Wasm modules.
- Use existing C/C++ libraries in PHP applications.
- Reduce server load through optimized binary code.
In this article, we will look at how to integrate WebAssembly with PHP in practice: from loading a module to passing data and processing results.
1. Basics of Working with WebAssembly in PHP
To work with Wasm in PHP, the wasm extension (or wasmer for PHP) is used. Installation is done via Composer:
composer require wasm/wasmAfter installation, you can load and execute Wasm modules. Let's look at a simple example: a C module that sums two numbers.
First, compile the C code into Wasm:
// sum.cint add(int a, int b) { return a + b;}Compilation (requires Emscripten or wasi-sdk):
emcc sum.c -o sum.wasm -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]'Now load the module in PHP and call the function:
<?phpuse Wasm\\Instance;use Wasm\\Module;
// Load the binary file$wasmBytes = file_get_contents('sum.wasm');$module = new Module($wasmBytes);$instance = new Instance($module);
// Call the exported add function$result = $instance->add(10, 20);echo "Result: " . $result; // 30?>The code is simple and intuitive: we create an instance of the module and call its functions as methods of a PHP object. It's important to remember that Wasm functions work with primitive types (int, float), so complex data structures require additional processing.
2. Passing Complex Data: Strings and Arrays
WebAssembly only operates with numbers. To pass strings or arrays, you need to allocate memory inside the Wasm module and pass pointers. Let's look at an example with string processing.
Let's create a C module that converts a string to uppercase:
// uppercase.c#include <string.h>#include <ctype.h>
void to_upper(char* str, int len) { for (int i = 0; i < len; i++) { str[i] = toupper(str[i]); }}Compile with exported memory functions:
emcc uppercase.c -o uppercase.wasm -s WASM=1 -s EXPORTED_FUNCTIONS='["_to_upper", "_malloc", "_free"]' -s ALLOW_MEMORY_GROWTH=1PHP code for calling:
<?php$wasmBytes = file_get_contents('uppercase.wasm');$module = new Module($wasmBytes);$instance = new Instance($module);
$input = "hello webassembly";$len = strlen($input) + 1; // +1 for null terminator
// Allocate memory in the Wasm module$ptr = $instance->malloc($len);// Write the string to the module's memory$instance->memory->write($ptr, $input);
// Call the transformation function$instance->to_upper($ptr, $len);
// Read the result from memory$result = $instance->memory->read($ptr, $len);echo "Result: " . trim($result); // HELLO WEBASSEMBLY
// Free the memory$instance->free($ptr);?>This approach requires manual memory management, but gives you full control over the data. To simplify, you can use wrapper libraries, such as wasm-php-bridge.