On Sat, May 16, 2026, at 10:19 AM, Go Kudo wrote:
> Hi internals,
>
> I'd like to start the discussion for a new RFC, OPcache Static Cache.
>
> RFC: https://wiki.php.net/rfc/opcache_static_cache
> Implementation: https://github.com/php/php-src/pull/22052
>
> The proposal adds an OPcache-managed shared-memory cache for explicit 
> userland values and for selected PHP static state. It introduces 
> explicit functions under the OPcache namespace (volatile_* and 
> persistent_*) and two attributes, #[OPcache\VolatileStatic] and 
> #[OPcache\PersistentStatic], that let selected static properties and 
> method static variables survive across requests. The feature is 
> disabled by default and only activates once memory is allocated through 
> the new INI directives.
>
> The RFC covers the motivation, the deliberate split between the two 
> backends, the trust model (one PHP runtime = one trust domain; this is 
> not a tenant isolation boundary), and benchmarks against APCu on NTS 
> php-fpm and ZTS FrankenPHP. The PR is the full implementation, with 
> PHPT coverage summarized in the Validation section.
>
> One thing to flag on the implementation status: the Windows build is 
> currently broken. I don't have a Windows development environment 
> available yet — one is being arranged through work, and I'll get the 
> Windows side fixed once that's in place.
>
> Feedback welcome.
>
> Best Regards,
> Go Kudo

Interesting!  I can definitely see uses for it, and I appreciate the level of 
detail in the RFC.

Some thoughts, though:

- atomic-decrement throwing if a value doesn't exist sounds like a footgun.  
For something like an up/down voting widget, I could very easily see someone 
hitting the Down Vote button first, which would cause it to crash.  Having to 
always check _exists() on decrement but not on increment is inconsistent and 
likely to confuse people.

- Are either of these stores purged on reboot?  

- "persistent cache and returns void on success." - No, returns null.  You 
can't return void.  A function can have a void return type, whether it's 
successful or not.  Not quite the same thing.

- Having the locks automatically self-unlock sure sounds elegant at first, but 
the lack of symmetry in the API feels very error prone.  People will want to 
use it like a transaction, but since it unlocks on the first write there's no 
way to make it one.  It just silently unlocks if certain functions are called.  
But if they're not called, there's no way to unlock it.  That's even more of an 
issue in a persistent-process use case, where you could easily not hit the 
process-end for minutes or hours, so the lock never automatically clears.

Use case: You need to update some lookup table, so you lock the stored key, 
compute the new table, then write the new table.  But if the compute step fails 
for some reason, you now have a locked value with no way to unlock it, but no 
new value to write to it.  It's better in many cases to leave the stale data 
there rather than delete it, but this API doesn't offer a way to do that.

- It's not made clear: Do objects have their __serialize() methods called when 
storing (and vice versa on load), or no?  "They have to be serializable" is not 
something that can be otherwise determined.

- Status API: Uh, what are the keys?  No arrays here please.  Please make it an 
object with defined readonly properties.  Please.

- You realize you're effectively adding a Memoize attribute to PHP by another 
name, right?  Just making sure. :-)

- A property using the volatile-tracking strategy, if run in a persistent 
process, seems like it would never get written.  That feels like a problem.

- The section on write times is rather abstract and academic, so a bit hard to 
follow.  If I read correctly, though, it means that writing to a sub-property 
of an array/object on a cached property won't trigger a resave?  That feels 
like another footgun waiting to happen.

- It's not clear if there's a way to clear an attribute-cached value other than 
nuking the entire volatile/persistent cache.  Is there not?  It feels like 
there should be one...  Especially for "persistent," I don't want to have to 
nuke my entire "persistent" cache from orbit because one value got corrupted 
somehow.

- Defaulting off... I can see the argument for that, but that means it will be 
off for most users.  That means I, as a library author of, say, a routing 
system or a DI container, cannot use it, because I have to assume most users 
won't have it.  That kneecaps the usefulness of this feature dramatically.  I 
would strongly recommend setting at least some default-on amount, even if it's 
only the minimum 8 MB, if we want this feature to actually be used.  (And I can 
already think of a few places where I'd want to use it myself.)

- Related, what happens if they're disabled but someone tries to use this 
functionality?  Does it operate like every read is a cache miss, or does it 
error?  If the latter, that means any code that uses the attributes REQUIRES 
that the ini directives be turned on.  We generally try to avoid this kind of 
"your code may or may not work depending on ini settings" issues.  (Hello, 
magic_quotes!)

- What's the development experience with this?  Frequently, in dev mode 
frameworks will disable caches.  If the volatile cache just misses silently 
that would work there, but not for the persistent cache.  How would I have a 
persistent route cache that is automatically rebuilt on every request during 
development while I'm messing with routes?

- I understand the value of keeping it simple by making it single-tenant.  
However, I can very easily see different 3rd party libraries wanting to make 
use of the cache at the same time.  That poses a risk of key-space collision, 
though that's resolvable by a convention to use a key prefix.  What it does not 
resolve is cases where one library wants to wipe-and-rebuild a dynamic list of 
keys, but some other library isn't expecting a total purge.  There's a high 
risk of libraries stepping on each other here.

- Currently, this is just a basic key/value store.  That's great for many 
things, but not very queryable.  This is absolutely scope creep, but would 
there be some way to extend this (in a future RFC, I'm sure) to allow, say, a 
persistent memory-resident SQLite database?  Currently you can write one to 
disk, but then you have to deal with disk permissions.  A memory resident 
database now is request-specific, so not useful outside of testing.  It would 
be lovely if there were some way to extend in that direction.

--Larry Garfield

Reply via email to