On Sun, Jun 28, 2026 at 1:23 AM Rowan Tommins [IMSoP]
<[email protected]> wrote:

> That "most probably" is doing a lot of work. Let me give a real-world
> example:
>
> google/apiclient depends on monolog/monolog, which in turn depends on
> psr/log
>
> The following code will give you an object which is an instance
> Monolog\Logger, and an instance of Psr\Log\LoggerInterface:
>
> $client = new \Google\Client;
> $logger = $client->getLogger();
>
> But:
>
> - the current version of google/apiclient can use either version 2.x or
> 3.x of monolog/monolog
> - the 3.x series of Monolog is compatible with both version 2.0 and 3.0
> of psr/log
> - the 2.x series is compatible with 1.0.1, 2.0, and 3.0 of psr/log
>
> So even with the exact same version of the \Google\Client class, there
> are 6 different combinations which might be installed.
>
> Now what happens if I instead run this:
>
> $client2 = $container->run(fn() => new \Google\Client);
> $logger2 = $client2->getLogger();
>
> Even if I detect somehow that $client2 is the same version of
> Google\Client I'm using, $logger2 can be any of the 6 different
> combinations.

Thanks for the example, it is a very interesting edge-case. But I think
even this situation is solvable. First, why do I consider it an edge-case.
In my vision, the primary use of containers would be through supplying
proper autoloaders for them. In this case, all code inside the container
and which relies by default on autoloading (which is the majority of cases)
will load all classes in a way we expect with corresponding tags. And so we
would be able to easily match all classes.

Your case differs from that because, as I understand it, it loads classes
manually depending on the conditions. In this case those classes would be
loaded with some meaningless tag for us as a creator of the container, in
other words $logger2 would be an instance of (<some_tag>, Logger). But we
could theoretically still match this class against known versions to us.
For this PHP could introduce alternatives to strict "instanceof". Let's
consider this example: we have some class defined in src/MyClass.php, and
it has been loaded twice with different tags: tag1 and tag2.

In this case $a = ("tag1", MyClass) is not an instance of ("tag2", MyClass)
in a strict (or formal) way. But since it is still the same class
internally (and PHP would be aware of that), we could have a less formal
"instanceof" which would give us true when comparing them. So, coming back
to your example, if we need to strictly map returned logger to our own
symbols, we could try to match it against all known/expected versions of
Logger, like:

use Monolog\Logger\Logger; // our "default" logger
use Monolog\Logger\Logger tagged "1.0" as LoggerV1;
use Monolog\Logger\Logger tagged "2.0" as Logger V2;

$client2 = $container->run(fn() => new \Google\Client);
$logger2 = $client2->getLogger();

match (true) {
    $logger2 instanceof Logger => ...., // here I mean less formal instanceof
    $logger2 instanceof LoggerV1 => ...,
    $logger2 instanceof LoggerV2 => ...,
}

Even though $logger2 would not strictly match to our imported symbols
because it has a meaningless tag to us, we could match it less strictly. In
fact, as it seems to me, such less formal comparison would make sense as a
default behaviour for instanceof.

> If the idea is that two containers somehow know to give a class entry
> the same tag, I don't think it's possible; in the example above, the
> "tag" for Google\Client needs to describe not just its own version, but
> which of the six possible combinations its getLogger() method will return.

Well, as I've said, in my vision autoloaders play an important role here
because it is them who decide which tag to attach to loaded classes. And in
this case all classes loaded inside the container could have meaningful
tags for us as a calling side.

> Again, if the "tag" somehow identifies a *container*, this could work;
> but as I mentioned in my first reply, identifying containers by name
> seems like it would just re-create the name collision problem we're
> trying to solve.

In my vision, "tag" does not really identify the container. It is whatever
we wish semantically. For example, let's say we're using Monolog\Logger 2.0
as our "default" logger. But we also use another library which is designed
for 1.0. And for us that Logger from version 1.0 would be identified as
("1.0", Logger) according to the semantics we've chosen and which is
reflected in our autoloader.

While running inside the container, this library will create its own logger
as it would do without any container (assuming it relies on autoloading).
For it it will still just be a Monolog\Logger\Logger class in exactly the
same way as it works now. And it will eventually return this logger to us.
But since it was loaded using the autoloader which we gave to the
container, for us it will already be not just some "unknown" Logger, but
exactly ("1.0", Logger) in our "host" semantics. And as I've described
earlier, even if the library does not rely on autoloading, "their" logger
would not be that meaningful to us directly, as it would have whatever tag.
But we could still match that (<whatever>, Logger) to our own ("1.0",
Logger).

> This is what I mean about "module-like" - the code inside the container
> has to be modified to be aware of which classes belong to which
> packages, and how to annotate them with the correct versions. And what
> if some code inside the container has been edited, so doesn't correspond
> to any official version?
>
> A DockerFile defines exposed ports, and file system mount points; it
> doesn't define a list of packages and their versions which another
> container can reach in and interact with.

I hope I could explain why no existing code has to be modified to be usable
inside containers, at least as I see it. No need to explicitly "expose"
anything from 3rd-party code. All the "management" would be done on the
calling side. But speaking about the example you provided with google
client, it is a good example why such "polymorphic" libraries themselves
would benefit from such class-versioning and containerization and would
themselves want to switch to it to get rid of all that compatibility
shenanigans.

Reply via email to