PHP GUI uses PHP's FFI (Foreign Function Interface) extension to bridge PHP code with native Tcl/Tk libraries. This enables building desktop GUI applications in pure PHP without any compiled extensions.
PHP Application
↓
Widget Classes (Window, Button, Label, ...)
↓
ProcessTCL (FFI Singleton)
↓
Native Tcl/Tk C Libraries
↓
OS Window Manager
The ProcessTCL class is the FFI singleton that:
- Loads the native Tcl/Tk library via FFI
- Detects the platform (Linux, Windows, macOS) and loads the appropriate binaries
- Executes Tcl commands from PHP
- Manages a callback registry mapping unique IDs to PHP closures
- Supports both Tcl 8.6 and Tcl 9.0
The Application class manages the event loop:
- Initializes the Tcl/Tk environment
- Continuously calls
updateto process Tcl events - Polls for callback triggers via temp files
- Manages the application lifecycle (start/stop)
The base class for all widgets:
- Assigns unique IDs via
uniqid() - Manages parent-child widget relationships
- Provides layout methods:
pack(),grid(),place() - Converts PHP option arrays to Tcl option strings
The event system uses a temp-file bridge pattern:
- A Tcl event fires (e.g., button click)
- The callback ID is written to
/tmp/phpgui_callback.txt - The
Applicationevent loop detects this file - It looks up the PHP closure by ID and executes it
- The temp file is cleaned up
This approach bridges Tcl's event system with PHP's synchronous execution model.
The library bundles native Tcl/Tk binaries for all platforms, so no system installation is required:
| Platform | Libraries |
|---|---|
| Linux | libtcl8.6.so, libtk8.6.so + X11 dependencies |
| Windows | tcl86t.dll, tk86t.dll |
| macOS | libtcl9.0.dylib, libtk9.0.dylib |
The WebView widget uses a helper process model instead of FFI. A small native binary hosts the platform's browser engine and communicates with PHP over JSON-over-stdio IPC.
PHP Application
↓
WebView Widget (PHP)
↓ JSON/stdio IPC
webview_helper binary (C++)
↓
Platform Browser Engine
├── WebKitGTK (Linux)
├── WKWebView (macOS)
└── WebView2 (Windows)
| Aspect | Tcl/Tk Widgets | WebView |
|---|---|---|
| Rendering | Native Tk controls | HTML/CSS/JS in browser engine |
| Bridge | FFI (in-process) | Separate helper process + IPC |
| Base class | Extends AbstractWidget |
Standalone (no inheritance) |
| Communication | Tcl commands | JSON messages over stdin/stdout |
Messages are newline-delimited JSON objects with a version field:
{"version":1,"cmd":"navigate","url":"https://example.com"}
{"version":1,"event":"ready"}
{"version":1,"event":"command","name":"greet","id":"0","args":"[\"Alice\"]"}- Commands (PHP → Helper):
navigate,set_html,set_title,set_size,eval,init,bind,unbind,return,emit,ping,destroy - Events (Helper → PHP):
ready,closed,command,error,pong
The helper binary is platform-specific and auto-downloaded from GitHub Releases on first use:
| Platform | Binary |
|---|---|
| Linux x86_64 | webview_helper_linux_x86_64 |
| macOS ARM | webview_helper_darwin_arm64 |
| macOS Intel | webview_helper_darwin_x86_64 |
| Windows x64 | webview_helper_windows_x86_64.exe |
If auto-download fails, build from source: cd src/lib/webview_helper && bash build.sh
The project uses PSR-4 autoloading:
PhpGui\→src/PhpGui\Widget\→src/Widget/