TALK
Design Patterns
in NativePHP
Design patterns under pressure in the NativePHP v4 render cycle
The shape of the nine.
Nine design patterns under pressure inside the NativePHP v4 render cycle — where PHP drives SwiftUI and Compose with no webview and no JSON bridge. One request, followed all the way — pipeline order is the argument.
One entry point that routes every request to the object that handles it.
A DSL with an evaluation step — Tailwind-looking syntax, but nothing CSS ever touches it.
→ fontSize(72)
native:column
Elements form a tree — screen → column → text + button. Higher-level components you compose flatten; only primitives appear in the published tree.
+ render()
@press="refresh" is registered and replaced with a stable callback ID. Nodes reference handlers by ID; the native event carries the ID back; PHP resolves it to your method.
If only part of the tree changed, unchanged subtrees become tiny reuse markers instead of being re-encoded.
encoded once
spliced thereafter
The Element Runtime writes each element into shared memory as a node, atomically bumps the frame version, and wakes the native reader — all on the PHP thread, off the UI thread.
no locks on the hot path
+ mount()
A dedicated reader thread decodes the nodes and diffs against the tree it rendered last time. Reuse markers are spliced from the previous tree without decoding. SwiftUI and Compose re-render exactly the views whose nodes changed.
right now
just published
One abstraction — the node — against two independently varying implementations. Flexbox values on each node drive a native Layout implementation per platform.
not PHP
not PHP
v3: the PHP object was a proxy for native state. v4: native owns the value; PHP holds a handle. The pattern didn’t change — the direction of ownership did.
the book’s picture
the same picture, in v4
— the handle
on the UI thread
full frame rate
Every one of these is a forced move at a boundary — and the cycle resolves into something you can watch happen.
Check my work.
Every row below is a claim from the talk. Documented rows quote the NativePHP v4 docs verbatim — the exact line is shown. Interpretation rows are my own reading: the Gang-of-Four pattern names are mine to argue for, not the docs'. Quotes are unedited; links go to the page they're pulled from.
| Claim in the talk | Type | Source | Exact line from the docs |
|---|---|---|---|
| The PHP runtime is embedded inside the app process; it talks to native over shared memory, not sockets. | Documented | Embedded PHP | "PHP ships inside your app as a library"; "there's no FastCGI, no sockets, no per-request process to spawn"; "shared memory only works when both sides share a process." |
| The Element Runtime is a PHP extension — native code compiled into libphp itself. | Documented | Embedded PHP Glossary | "The Element Runtime is a PHP extension — native code compiled into libphp itself, alongside the engine." |
| It ships as prebuilt binaries pinned to each release. | Documented | Embedded PHP | "every release of nativephp/mobile pins exact binary builds… produced and shipped together, from matching sources." |
| The pipeline has three phases: Render, Publish, Mount. | Documented | Render, Publish, and Mount | Doc page titled "Render, Publish, and Mount," describing all three stages. |
| Render: PHP builds an Element Tree. | Documented | Render, Publish, and Mount Glossary | "PHP builds an Element Tree describing what the screen should look like." |
Each native: tag
emits an Element — a plain PHP object. |
Documented | Render, Publish, and Mount Glossary | "Blade compiles the
template, and each native: tag emits an Element: a plain PHP
object describing one piece of UI." |
Utility classes like
p-4 / text-2xl are parsed into layout and style
values in PHP, not on the native side. |
Documented | Render, Publish, and Mount | "Utility classes like
p-4 and text-2xl are parsed into concrete layout and
style values at this stage." |
| Composed EDGE components flatten; only primitives reach the published tree. | Documented | Render, Publish, and Mount | "Higher-level EDGE components you compose yourself flatten into these primitives; only primitive elements appear in the tree." |
@press="refresh"
is registered and replaced with a stable callback ID. |
Documented | Render, Publish, and Mount Glossary | "event handlers like
@press="refresh" are registered and replaced with stable callback
IDs"; Callback ID: "native events carry the ID back, and PHP resolves it to
your method." |
| Publish: each element is written into shared memory as a node — a compact, fixed-layout binary record (type, layout, style, refs to props and handlers). | Documented | Render, Publish, and Mount Glossary | "writes each element into shared memory as a node: a compact, fixed-layout binary record carrying the element's type, layout, style, and references to its props and handlers." |
| The same pipeline runs for first paint and for every update after. | Documented | Render, Publish, and Mount | "The same pipeline runs for the first paint of a screen and for every update after it." |
| Unchanged subtrees become tiny reuse markers instead of being re-encoded. | Documented | Subtree Reuse | "any subtree whose fingerprint matches the previous frame is written as a single tiny reuse marker instead of being re-encoded." |
| An identical frame isn't published at all. | Documented | Subtree Reuse | "Identical frames are dropped on the spot — the native side is never even woken." |
| On mount, reuse markers are spliced from the previous tree without decoding. | Documented | Subtree Reuse | "The native reader splices the corresponding subtree from the tree it already has, without decoding anything." |
| A dedicated native reader thread decodes frames and diffs against the previous tree. | Documented | Render, Publish, and Mount Threading Model | "Each platform has a background thread that receives published frames, decodes them, and diffs them against the previous tree." |
| Publishing uses atomic version counters; it runs on the PHP thread, off the UI thread. | Documented | Threading Model | "atomic version counters on the shared region"; "the PHP thread wakes, runs your handler, re-renders and publishes." |
| The loop: press event (carrying a callback ID) → PHP thread wakes → runs the handler → publishes → reader thread diffs → UI thread mounts. | Documented | Render, Publish, and Mount Threading Model Glossary | "fires a press event carrying its callback ID into the event channel"; "the PHP thread wakes, runs your handler, re-renders and publishes → the reader thread diffs → the UI thread mounts the change." |
| Scroll, drag, and SharedValue-driven animation run on the UI thread frame-by-frame; PHP gets one discrete event, not a per-frame consult. | Documented | Threading Model About the New Architecture Glossary | "Gestures and animations driven by SharedValues are evaluated directly on the UI thread at the display's frame rate… PHP receives one event when the gesture completes." |
| The value lives on the native side; PHP holds a handle to it. | Documented | Glossary About the New Architecture | SharedValue: "A value that lives on the native side… PHP holds a handle." |
| One node abstraction, two native implementations; flexbox values drive a per-platform Layout. | Documented | Cross-Platform Implementation | "each platform implements flexbox inside its own layout system — a pure-Swift Layout on iOS and a Compose Layout on Android." |
| It renders to SwiftUI on iOS and Jetpack Compose on Android. | Documented | Render, Publish, and Mount Cross-Platform Implementation SuperNative Introduction (docs) | "a renderer that maps each node type to a SwiftUI view or a composable." |
| SuperNative is the default architecture in v4; the web view is opt-in per screen. | Documented | Blog: SuperNative | "SuperNative is the
default architecture"; web view is "explicitly opt-in" via
<native:webview>. |
| The UI render/update path has no serialization step and no web-view bridge. | Documented | SuperNative Introduction (docs) | "no network round-trip, no serialization overhead, and no waiting on a web view bridge." |
super-native is a
beta reference app, not for production. |
Documented | Reference app (super-native) | "Not for production. This is a reference app for exploring NativePHP's Element rendering system." |
| Reading the render pipeline as a chain of Gang-of-Four patterns — Interpreter, Composite, Command, Bridge, Proxy (plus Producer/Consumer and Reconciliation, which aren't GoF) — and arguing each is a "forced move" at a boundary. | Interpretation | — | The speaker's framing. Every pattern sits on a documented mechanism cited above; the names and the "forced move" thesis are the argument of the talk, not claims in the docs. |
| The node-vs-platform split, presented as the Gang-of-Four Bridge pattern. | Interpretation | Cross-Platform Implementation | Mechanism is documented (see the per-platform Layout row); calling it "Bridge" is the speaker's reading. |
The sources.
- S1 Render, Publish, and Mount nativephp.com
- S2 Subtree Reuse nativephp.com
- S3 Threading Model nativephp.com
- S4 Embedded PHP nativephp.com
- S5 Cross-Platform Implementation nativephp.com
- S6 Glossary nativephp.com
- S7 SuperNative Introduction (docs) nativephp.com
- S8 About the New Architecture nativephp.com
- S9 Blog: SuperNative nativephp.com
- S10 Reference app (super-native) github.com
Claims verified against the live NativePHP v4 docs on 2026-07-30. NativePHP v4 is a public beta; APIs may change and the reference app is explicitly not for production.