On Sat, Jun 13, 2026 at 6:32 AM Alex "Pierstoval" Rock <[email protected]>
wrote:
>
> Containers as "code block that's executed in another thread" seems like
> something completely different than implementing modules, or am I missing
> something?
>
It gives you what you're looking for without having to overhaul the
language in any massive way. I made the prior post on my phone where it's
hard to make a message, but I'm on my computer this morning so I can
elaborate now. And while elaborating, I realized this probably needs it's
own discussion thread entirely because it can solve not just the original
plugin problem, but also the process workers problem if handled correctly.
Let's review.
PHP's ecosystem has packages already. It doesn't need modules as seen in
JavaScript. What it needs in certain corner cases is better package
isolation: The ability for a package to do its thing without disturbing or
being disturbed by outside code. Drupal, Laravel, Symfony, et al do a great
job of isolating their libraries, but they still have to register their
class names and constants on the global name table. Under the hood
Namespaces in PHP are a bit of a hack - they prepend the stated namespace
to all labels declared in the file, and the use statement allows the fully
qualified name of a class, function or constant to be stated only once,
usually at the head of the file. It also allows aliasing, say if you have a
"Parser" class out of two different packages - you can alias them as
"FooParser" and "BarParser". It looks like Java or JavaScript importing,
but it isn't.
The global namespace of PHP, both for variables and constants, is limited
to the current thread. PHP isn't natively multithreaded - there's a whole
other RFC on async/await in progress. What I'm about to go over would
benefit from that work, but it isn't a prerequisite to implementing
containers.
A container is an interface to a PHP process on another thread. It takes
the form of an object that is returned by the included file. Where returns
are optional for include/require, the new statement require_container
mandates that an object be returned. I'd go even further and mandate that
the object must implement a ContainerInterface that is added to PHP core.
By virtue of running on its own thread a container has its own symbol table
both for constants/classes/functions but also for variables. It is further
restricted by having no superglobals - no $_REQUIRE, $_POST, $_GET, etc. If
it needs to work with these then they'll have to come in through the
interface from the outside code, or perhaps a PHP internal function can
supply them with their own copy of these variables, but crucially any
modification they make will not affect other containers.
When PHP starts a container, it will cache the returned code and hand over
a copy. This differs slightly from normal OP_Cache which caches the
bytecode of the file itself so that new parsing isn't needed. It was at
this moment I realized that two problems, not one, get solved by this.
Let's start with the original though, package isolation. We'll use Guzzle
for an example. The calling code
<?php
$guzzle = require_container('path/to/guzzle/container/class')
?>
Now in PHP we've tried to get away from having to reference specific paths
like this. Coming up with ways to resolve that path can be done in userland
just as composer does this in userland. One example might look like this:
<?php
$guzzle = require_container(Container::getPath('Guzzle'))
?>
The required file might look like this, at least in part
<?php
use GuzzleHttp\Client;
require 'path/to/my/package/composer/autoloader';
return new GuzzleContainer implements Container {
public static getClient($options) {
return new Client($options);
}
}
?>
And I trust the folk who know how the engine works can clearly see if this
has a hope in Hell of working or not. I'm going to stop here for their
input. If it does though, here's the other problem that might be solved.
Here, we look at Drupal's existing entry index.php
<?php
use Drupal\Core\DrupalKernel;
require_once 'autoload_runtime.php';
return static function () { return new DrupalKernel('prod', require
'autoload.php');};
?>
Without digging deeply, suffice to say that "new DrupalKernel" call kicks
off a lot of config processing that has to be done before the request can
even start to be processed, and this is redundant to every request. Quite a
bit of caching is in play to reduce this burden as much as possible, but if
we have a container system, we can fetch a pre-built worker and avoid all
of it.
<?php
(require_container 'drupal_worker.php')->parse($_GET, $_POST, $FILES,
$_SERVER, $_SESSION);
?>
Remembering what I mentioned before, that the PHP Engine caches the
worker's state at the moment it is returned to the calling file. So it can
get its own autoloader setup and configuration parsing completely done and
be in a ready state to handle the request. It would likely require some
serious refactoring to fully take advantage of this, but the performance
gains should be very real.
Thoughts?