cto @les-tilleuls.coop / @symfony.com+#frankenphp+#php core team โข creator of ember
Alexandre Daubois
Loading...
Type inference is the secret weapon.
If OPcache proves $i is always an int in a loop, the JIT skips type checks at runtime.
That's how PHP 8 hot loops can match compiled-language perf.
opcache.optimization_level is a bitmask.
Default = 0x7FFEBFFF (almost everything ON).
Turn it off (0): hot paths slow down 20-30%.
Turn it ON without JIT: still a 5-15% boost.
OPcache doesn't just cache opcodes.
It runs a real compiler optimizer on them.
SSA form, dead code elimination, type inference. Yes, in #PHP ๐
ZTS (Zend Thread Safety): the #PHP layer most devs never see.
In ZTS mode, every global becomes thread-local. Each thread gets its own executor, compiler, module globals. Full isolation.
FPM doesn't need it: direct C globals, fastest path.
FrankenPHP does: it runs PHP inside Go threads.
๐งต
#PHP has inline caches and almost nobody knows ๐
$obj->name: first access does a hash lookup. But the engine stores the result offset in a "cache slot" embedded in the opcode.
Next time, same class? Direct read. No lookup. Works for methods, constants, type checks too.
Generators vs Fibers in #PHP: both suspend execution, totally different mechanism.
Generator: saves ONE execute_data frame. Yield pauses it, ->next() resumes. One level deep.
Fiber: saves the ENTIRE call stack.
Generator, stackless coroutine. Fiber, stackful coroutine.
That's why FrankenPHP requires ZTS builds: it's dealing with PHP threads all the way.
Want to see the optimizer's output yourself?
opcache.opt_debug_level=0x60000
Dumps pre-SSA, post-SSA, final opcodes.
Read it once, you'll see PHP differently forever.
What other interpreters surprise you with hidden compiler-grade optimizations?
First, OPcache builds a Static Single Assignment form of your function.
Each variable assigned exactly once. New "version" on every reassignment: $a, $a#1, $a#2...
This makes data flow obvious. Optimizers love it.
With SSA, the optimizer runs a series of passes:
- Constant propagation: `1 + 2` โ `3` at compile time
- Dead code elimination: unreachable branches deleted
- Type inference: tracks if $x is always int
- Function inlining: small calls expanded inline