# Folk Embed Runtime — Extension Compatibility Matrix
This matrix documents PHP extension compatibility with the Folk embed SAPI (`runtime = "embed"`).
## How to read
| **Load** | Extension loads without crash |
| **Basic** | Basic functionality works |
| **Multi-req** | Works across multiple request cycles |
| **Threads** | Safe with multiple worker threads |
| **Notes** | Known issues or limitations |
Status: ✓ = works, ✗ = fails, ⚠ = works with limitations, — = not tested
## Bundled PHP Extensions
| bcmath | ✓ | ✓ | ✓ | ✓ | Pure computation |
| bz2 | ✓ | ✓ | ✓ | ✓ | |
| calendar | ✓ | ✓ | ✓ | ✓ | Pure computation |
| ctype | ✓ | ✓ | ✓ | ✓ | |
| curl | ✓ | ✓ | ✓ | ✓ | Each thread gets own curl handles |
| date | ✓ | ✓ | ✓ | ✓ | |
| dom | ✓ | ✓ | ✓ | ✓ | libxml2 is thread-safe |
| exif | ✓ | ✓ | ✓ | ✓ | |
| ffi | ✓ | ⚠ | ✓ | ⚠ | User must ensure thread-safety of loaded libs |
| fileinfo | ✓ | ✓ | ✓ | ✓ | |
| filter | ✓ | ✓ | ✓ | ✓ | |
| ftp | ✓ | ✓ | ✓ | ✓ | |
| gd | ✓ | ✓ | ✓ | ✓ | Per-request image resources |
| gettext | ✓ | ✓ | ✓ | ✓ | |
| gmp | ✓ | ✓ | ✓ | ✓ | Pure computation |
| hash | ✓ | ✓ | ✓ | ✓ | |
| iconv | ✓ | ✓ | ✓ | ✓ | |
| intl | ✓ | ✓ | ✓ | ✓ | ICU is thread-safe |
| json | ✓ | ✓ | ✓ | ✓ | |
| ldap | ✓ | ✓ | ✓ | ✓ | Per-connection handles |
| mbstring | ✓ | ✓ | ✓ | ✓ | |
| mysqli/mysqlnd | ✓ | ✓ | ✓ | ✓ | Per-thread connections |
| openssl | ✓ | ✓ | ✓ | ✓ | Thread-safe since OpenSSL 1.1 |
| Zend OPcache | ✓ | ✓ | ✓ | ✓ | SHM shared between workers (read-only) |
| pcntl | ⚠ | ⚠ | ⚠ | ✗ | **fork() conflicts with threads** — do not use |
| pcre | ✓ | ✓ | ✓ | ✓ | |
| pdo | ✓ | ✓ | ✓ | ✓ | |
| pdo_mysql | ✓ | ✓ | ✓ | ✓ | |
| pdo_pgsql | ✓ | ✓ | ✓ | ✓ | |
| pdo_sqlite | ✓ | ✓ | ✓ | ✓ | |
| pgsql | ✓ | ✓ | ✓ | ✓ | |
| phar | ✓ | ✓ | ✓ | ✓ | |
| posix | ✓ | ✓ | ✓ | ✓ | |
| readline | ✓ | — | — | ✗ | Interactive — no use case in embed |
| reflection | ✓ | ✓ | ✓ | ✓ | |
| session | ✓ | ⚠ | ⚠ | ⚠ | File sessions need per-worker paths |
| shmop | ✓ | ✓ | ✓ | ⚠ | Shared memory — needs coordination |
| simplexml | ✓ | ✓ | ✓ | ✓ | |
| soap | ✓ | ✓ | ✓ | ✓ | |
| sockets | ✓ | ✓ | ✓ | ✓ | |
| sodium | ✓ | ✓ | ✓ | ✓ | Thread-safe |
| spl | ✓ | ✓ | ✓ | ✓ | |
| sqlite3 | ✓ | ✓ | ✓ | ✓ | Per-thread database handles |
| standard | ✓ | ✓ | ✓ | ✓ | |
| sysvmsg | ✓ | ✓ | ✓ | ⚠ | System V IPC — shared state |
| sysvsem | ✓ | ✓ | ✓ | ⚠ | System V IPC — shared state |
| sysvshm | ✓ | ✓ | ✓ | ⚠ | System V IPC — shared state |
| tidy | ✓ | ✓ | ✓ | ✓ | |
| tokenizer | ✓ | ✓ | ✓ | ✓ | |
| xml | ✓ | ✓ | ✓ | ✓ | |
| xmlreader | ✓ | ✓ | ✓ | ✓ | |
| xmlwriter | ✓ | ✓ | ✓ | ✓ | |
| xsl | ✓ | ✓ | ✓ | ✓ | |
| zip | ✓ | ✓ | ✓ | ✓ | |
| zlib | ✓ | ✓ | ✓ | ✓ | |
## PECL Extensions
| apcu | ✓ | ✓ | ✓ | ✓ | SHM shared between workers |
| igbinary | ✓ | ✓ | ✓ | ✓ | Serialization — stateless |
| imagick | ✓ | ✓ | ✓ | ✓ | ImageMagick is thread-safe |
| memcached | ✓ | ✓ | ✓ | ✓ | Per-thread connections |
| mongodb | ✓ | ✓ | ✓ | ✓ | Thread-safe driver |
| msgpack | ✓ | ✓ | ✓ | ✓ | Serialization — stateless |
| redis | ✓ | ✓ | ✓ | ✓ | Per-thread connections |
| uuid | ✓ | ✓ | ✓ | ✓ | |
| xhprof | ✓ | ✓ | ✓ | ⚠ | Profiling overhead — disable in production |
| yaml | ✓ | ✓ | ✓ | ✓ | |
### Known Incompatible
| pcntl | ⚠ Unsafe | `fork()` in threaded process = undefined behavior |
| parallel | ✗ | Own threading model, conflicts with embed workers |
| swoole/openswoole | ✗ | Own event loop and coroutines, conflicts with embed |
| xdebug | ⚠ | Thread-safety issues — use only for debugging, not production |
| pthreads | ✗ | Removed in PHP 8, but historically incompatible |
## Recommendations
1. **Safe for production**: All bundled extensions except pcntl, readline
2. **Database**: Use per-thread connections (PDO/mysqli with `new` per request)
3. **Caching**: APCu and OPcache work great (SHM shared between workers)
4. **Serialization**: msgpack, igbinary — fully thread-safe
5. **Avoid**: pcntl (fork), parallel (own threads), swoole (own event loop)
## Running Tests
```bash
# Full compatibility suite (Docker, all extensions)
docker build -f crates/folk-runtime-embed/compat/Dockerfile -t folk-compat .
docker run --rm folk-compat
# Local (tests whatever extensions are available)
cargo test -p folk-runtime-embed --test extension_compat -- --test-threads=1 --nocapture
```