This document evaluates different approaches for running PHPBoy in the browser via WebAssembly.
PHPBoy is written in PHP 8.5, which presents unique challenges for browser deployment. This evaluation explores three main approaches for bringing PHP code to the browser.
Description: Compiles the Zend Engine (PHP runtime) to WebAssembly, allowing native PHP execution in the browser.
Pros:
- ✅ Runs actual PHP code without transpilation
- ✅ Full PHP 8.x feature support (enums, readonly, typed properties, etc.)
- ✅ Active development and community
- ✅ Good documentation and examples
- ✅ Supports Composer dependencies
- ✅ Virtual filesystem for file operations
- ✅ Direct DOM manipulation via Vrzno bridge
- ✅ SQLite and database support built-in
- ✅ Works with major frameworks (Laravel, Drupal, etc.)
Cons:
⚠️ Large runtime size (~10-15 MB WASM file)⚠️ Slower startup time (loading PHP runtime)⚠️ Performance overhead vs. native JavaScript⚠️ Limited debugging tools in browser⚠️ Some PHP extensions unavailable
Performance:
- Startup: 2-5 seconds (loading WASM runtime)
- Execution: ~2-3x slower than native PHP
- Memory: ~20-50 MB baseline
- Frame rate: 40-60 FPS expected
Integration Complexity: ⭐⭐⭐ Medium
- Requires virtual filesystem setup
- JavaScript bridge for I/O
- Async API for PHP calls
Verdict: Best choice for PHPBoy. Preserves PHP code as-is, supports all language features, and provides acceptable performance.
Description: Transpiles PHP to JavaScript, which then runs natively in the browser.
Pros:
- ✅ Fast execution (native JavaScript performance)
- ✅ Smaller bundle size than WASM
- ✅ Better debugging (JavaScript source maps)
- ✅ No runtime loading overhead
Cons:
- ❌ Limited PHP version support (PHP 5.x-7.x)
- ❌ No PHP 8.x features (enums, readonly, match, etc.)
- ❌ Incomplete language coverage
- ❌ Not actively maintained
- ❌ Would require rewriting large portions of PHPBoy
- ❌ Type system incompatibilities
Performance:
- Startup: Fast (<1 second)
- Execution: Near-native JavaScript speed
- Memory: Lower than WASM
- Frame rate: 60 FPS expected
Integration Complexity: ⭐⭐⭐⭐⭐ Very High
- Requires significant code changes
- PHP 8.5 features must be rewritten
- Enum, readonly, typed properties unsupported
Verdict: Not suitable. PHPBoy heavily uses PHP 8.5 features that Uniter doesn't support. Would require complete rewrite.
Description: Another WASM-based PHP runtime, part of the Wasmer ecosystem.
Pros:
- ✅ Runs native PHP code
- ✅ Part of larger Wasmer ecosystem
- ✅ Good performance
Cons:
⚠️ Less documentation than seanmorris/php-wasm⚠️ Smaller community⚠️ Fewer examples and tutorials⚠️ Less frequent updates⚠️ Limited browser-specific features
Performance: Similar to seanmorris/php-wasm
Integration Complexity: ⭐⭐⭐⭐ Medium-High
- Less documentation for browser integration
- Fewer community resources
- May require more custom bridge code
Verdict: Not selected. While viable, seanmorris/php-wasm has better documentation and community support.
Description: Rewrite the entire emulator in JavaScript or TypeScript.
Pros:
- ✅ Best performance (native browser code)
- ✅ Smallest bundle size
- ✅ Best debugging experience
- ✅ No runtime loading
- ✅ Direct DOM/Canvas/WebAudio access
Cons:
- ❌ Requires complete rewrite (~10,000+ lines of code)
- ❌ Loses PHP implementation (main goal of PHPBoy)
- ❌ Months of development time
- ❌ Would need to maintain two codebases
Verdict: Not suitable. Defeats the purpose of PHPBoy, which is to showcase PHP for emulation.
| Option | PHP 8.5 Support | Performance | Bundle Size | Dev Effort | Maintenance |
|---|---|---|---|---|---|
| php-wasm | ✅ Full | ⭐⭐⭐ Good | Large | Low | Low |
| Uniter | ❌ None | ⭐⭐⭐⭐⭐ Excellent | Small | Very High | High |
| wasmerio | ✅ Full | ⭐⭐⭐ Good | Large | Medium | Medium |
| JS Rewrite | ❌ N/A | ⭐⭐⭐⭐⭐ Excellent | Small | Very High | High |
php-wasm is the clear choice for PHPBoy because:
-
Preserves PHP Code: The primary goal of PHPBoy is demonstrating PHP for game emulation. php-wasm allows us to use the exact same PHP code in the browser as in CLI.
-
PHP 8.5 Support: PHPBoy extensively uses PHP 8.5 features:
- Enums for opcodes and state machines
- Readonly properties
- Typed class constants
- Property hooks
- Strict types
- Match expressions
-
Minimal Changes: Only I/O layer needs adaptation (framebuffer, audio, input). Core emulation logic remains unchanged.
-
Active Development: Regular updates and responsive maintainer.
-
Good Documentation: Clear examples and community resources.
-
Acceptable Performance: While slower than native JS, it's fast enough for Game Boy emulation (60 FPS achievable).
-
I/O Abstraction: Create WASM-specific implementations of:
WasmFramebuffer- buffers pixels for CanvasWasmAudioSink- buffers audio for WebAudioWasmInput- receives keyboard/touch input
-
JavaScript Bridge: Create
phpboy.jsto:- Initialize php-wasm runtime
- Load ROM into virtual filesystem
- Drive emulation loop via
requestAnimationFrame - Transfer pixel data to Canvas
- Transfer audio data to WebAudio
- Pass input events to PHP
-
Build System: Create
make build-wasmtarget to:- Copy web files (HTML, CSS, JS)
- Copy PHP source and dependencies
- Generate distribution directory
To achieve 60 FPS:
- Minimize PHP-JS calls: Batch operations where possible
- Use typed arrays: For efficient pixel/audio data transfer
- Optimize emulation loop: Call PHP once per frame, not per instruction
- Pre-warm caches: Initialize instruction set upfront
- Larger Bundle: ~15 MB for PHP runtime (acceptable for modern web)
- Startup Time: 2-5 seconds to load PHP (one-time cost)
- Performance: ~40-60 FPS vs. 60+ FPS in CLI (acceptable for web demo)
A minimal "Hello World" proof-of-concept was created to validate the approach:
import { PhpWeb } from 'php-wasm/PhpWeb.mjs';
const php = new PhpWeb();
await php.binary; // Wait for runtime
const result = await php.run(`<?php
echo "Hello from PHP in the browser!";
`);
console.log(result.body); // "Hello from PHP in the browser!"✅ Success: PHP runtime loads and executes successfully in Chrome, Firefox, and Safari.
php-wasm is the optimal choice for bringing PHPBoy to the browser. It preserves the PHP implementation, supports all language features, and provides acceptable performance for Game Boy emulation. The development effort is minimal (mainly I/O adapters), and the result is a true demonstration of PHP running a game emulator in the browser.