syntaxx/phpx-framework
Composer 安装命令:
composer require syntaxx/phpx-framework
包简介
PHPX Framework - A modern PHP framework with JSX-like syntax support
README 文档
README
React-style components, written in PHP. A small, isomorphic UI runtime: the same component renders on the server (SSR) and runs in the browser as PHP compiled to WebAssembly, then hydrates to interactive — keeping input focus and caret across re-renders.
Status: Technology Preview. The core (reconciler, hooks, SSR + hydration, Suspense, router) is solid and tested, but APIs may change and the edges are sharp. Not production-ready yet.
function Counter($props) { [$count, $setCount] = useState(0); return ( <div className="text-center"> <h1>Count: {$count}</h1> <button onClick={fn() => $setCount($count + 1)}>+</button> </div> ); }
The same Counter is server-rendered to HTML and then hydrated in the browser —
no separate JavaScript implementation, no hydration-mismatch class of bugs.
What it is (and isn't)
- A persistent-instance virtual-DOM reconciler (Preact-class): keyed diffing, surgical DOM patching, focus/caret preservation. It is not React Fiber — rendering is synchronous; there is no scheduler, no time-slicing, no concurrent mode.
- Isomorphic by construction: one tree renders through a pluggable host config to real DOM (browser), an HTML string (server), or an in-memory fake (tests). Server and client seed the same hydration state.
- Pure PHP. The browser runtime is PHP-in-WASM via the VRZNO DOM bridge; on the server it's ordinary PHP.
Installation
composer require syntaxx/phpx-framework
Requires PHP 8.4+ (developed and tested on PHP 8.4). The hook functions are
registered globally via Composer's files autoload, so they're available
everywhere once the autoloader is loaded.
Writing JSX-in-PHP (
<div>…</div>) requires the PHPX compiler, which transforms it into the plainComponent::create(...)calls shown below. For a full project (compiler + WASM build + dev server) start from the PHPX starter kit rather than wiring this package up by hand.
Components
A component is a plain function that takes $props and returns an element tree.
function Greeting($props) { return <p>Hello, {$props['name']}!</p>; }
- Capitalized names are components (resolved from global functions);
lowercase names are host elements (
div,button, …). - Without the compiler, elements are created directly:
use Syntaxx\PHPX\Framework\Component; Component::create('div', ['className' => 'card'], [ Component::create('Greeting', ['name' => 'world'], []), ]);
- Events use
on*props with PHP callables:onClick,onInput,onKeyPress, … (onDoubleClick→dblclick). Handlers are delegated — one root listener per event type — so they survive re-renders untouched.
<input value={$text} onInput={fn($e) => $setText($e->target->value)} />
Hooks
All hooks are global functions (no use needed):
| Hook | Signature | Purpose |
|---|---|---|
useState |
useState($initial, ?string $hydrationKey = null): [$value, $setValue] |
Local state; supports functional updates and === bail-out |
useEffect |
useEffect(callable $fn, ?array $deps = null): void |
Side effects after commit (never runs on the server) |
useRef |
useRef($initial = null): Ref |
Stable mutable container ($ref->current); auto-binds to the host node when passed as a ref prop |
useMemo |
useMemo(callable $factory, array $deps): mixed |
Memoized value |
useCallback |
useCallback(callable $cb, array $deps): callable |
Memoized callback |
useData |
useData(string $key, callable $fetcher): [$data, $loading, $error] |
Isomorphic data: server fetches + seeds, client reads the seed (fetches once if unseeded) |
useSuspenseData |
useSuspenseData(string $key, callable $fetcher): mixed |
Returns the value or throws a Suspension caught by the nearest <Suspense> |
Standard rules of hooks apply: call them unconditionally and in the same order every render.
Server-side rendering + hydration
Render to HTML on the server:
use Syntaxx\PHPX\Framework\{Component, ServerRenderer}; $result = ServerRenderer::render( Component::create('App', [], []), [], // explicit initial state (optional) ['pathname' => $path, 'search' => $search] ); echo "<div id=\"root\">{$result['html']}</div>"; echo ServerRenderer::stateScript($result['state']); // <script id="__phpx_state__">…</script>
Hydrate the same tree in the browser (PHP-in-WASM entry point):
use Syntaxx\PHPX\Framework\{Component, Runtime, Router}; $root = Runtime::hydrateRoot($document->getElementById('root')); $render = fn() => $root->render(Component::create('App', [], [])); $render(); Router::start($render); // client-side navigation re-renders without rebooting WASM
Streaming SSR
StreamRenderer::stream($component, $state, $location) yields shell,
boundary, and close chunks so the shell (with <Suspense> fallbacks) flushes
first and boundary content streams in as data settles.
Routing
A minimal History-API router:
Router::start(callable $onChange)— intercept internal link clicks + popstate.Router::navigate(string $href)— programmatic navigation.Router::current(): array—['pathname' => …, 'search' => …].Environment::location()/Environment::isServer()— read location isomorphically.
Routing is flat pathname matching today (no route params or nested routes yet).
Architecture
Component tree ─▶ Reconciler ─▶ HostConfig backend ─▶ output
(keyed diff, ├─ VrznoBackend → real DOM (browser)
surgical ├─ SsrBackend → HTML string (server)
patching) └─ FakeDomBackend→ in-memory (tests)
The reconciler keeps persistent nodes across renders and applies only the minimal
set of mutations, which is what preserves focus, caret, scroll, and media state.
Hooks are bound to those persistent instances. The HostConfig interface lets you
render to any target.
What's implemented
- ✅ Components, props, children, fragments
- ✅ Hooks:
useState,useEffect,useRef,useMemo,useCallback,useData,useSuspenseData - ✅ Delegated events with a synthetic-event object
- ✅ Keyed reconciliation + surgical DOM patching (focus-preserving)
- ✅
<Suspense>and streaming SSR - ✅ SSR + hydration (isomorphic, state-seeded)
- ✅ Client-side router
- ⬜ Context API,
useReducer - ⬜ Route params / nested routes / route data loaders
- ⬜ Concurrent / interruptible rendering
Testing
composer install vendor/bin/phpunit
Tests run headlessly against an in-memory FakeDomBackend (no browser needed) and
cover the reconciler, hooks, hydration, SSR, and Suspense.
Where this fits
PHPX Framework is one module of the Syntaxx / PHPX ecosystem:
- PHP-X-Parser — JSX grammar + AST for PHP
- PHPX-Compiler — transforms JSX-in-PHP → plain PHP
- PHPX-BuildTools — build/pack/export/serve for WebAssembly projects
- PHPX-WasmRuntimeVrzno — the PHP-WASM browser runtime (VRZNO)
- PHPX Framework — this package: the component runtime
License
MIT
syntaxx/phpx-framework 适用场景与选型建议
syntaxx/phpx-framework 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 59 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 10 月 26 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 syntaxx/phpx-framework 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 syntaxx/phpx-framework 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 59
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 22
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-10-26