On Tue, May 13, 2025, 9:32 a.m. Deleu <deleu...@gmail.com> wrote:

> Hi!
>
> It's been a few days since I wanted to send this email to internals, but
> real life has been a bit chaotic so I apologize if it comes off as if I
> didn't research the archives enough. I glossed over the Module conversation
> from 10 months ago and the one that recently surfaced and after deeply
> thinking about Rowan's and Larry's comments I wanted to throw this idea
> into the pit.
>
> Lets preface the conversation with the fact that 1) a module system for
> PHP has been discussed for several years and 2) if there was an easy and
> perfect solution it would have been long implemented by now. With that in
> mind, I think there are mainly two major "camps": the ones that would
> support something new similar to Node ESM vs CommonJS and those who won't.
> Having dealt with this mess on the NodeJS side, I'm still on the side that
> would support it because even though it's been 10 years worth of "mess", it
> has greatly empowered progress. But I think PHP is too conservative to
> indulge this camp, so I'm going to focus on Rowan's and Larry's position of
> "we need something that builds on top of namespace, not replace it".
>
> If we consider how GitHub, Composer and Docker Hub works, we can pin a
> very important aspect of "namespaces": {entity}/{project}. Entity may
> either be an individual or an organization, but the concept is mostly the
> same. Although it can be argued that PHP has nothing to do with that, I
> think that could be a "good-enough" foundation considering the complexity
> of the subject. Here is what we could do:
>
> ```php
>
> <?php declare(strict_types=1);
>
> namespace Acme\ProjectOne
> {
>     public class Foo {} // same as class Foo {}
>
>     private class Bar {} // only visible inside Acme\ProjectOne
>
>     protected class Baz {} // visible inside Acme
> }
>
> namespace Acme\ProjectTwo
> {
>     new \Acme\ProjectOne\Foo; // Work as always
>
>     new \Acme\ProjectOne\Bar; // Fatal error: Uncaught Error: Cannot 
> instantiate private class \Acme\ProjectOne\Bar from \Acme\ProjectTwo
>
>     new \Acme\ProjectOne\Baz; // Works
> }
>
> namespace Corp\Corp
> {
>     new \Acme\ProjectOne\Foo; // Work as always
>
>     new \Acme\ProjectOne\Bar; // Fatal error: Uncaught Error: Cannot 
> instantiate private class \Acme\ProjectOne\Bar from \Corp\Corp
>
>     new \Acme\ProjectOne\Baz; // Fatal error: Uncaught Error: Cannot 
> instantiate protected class \Acme\ProjectOne\Baz from \Corp\Corp
> }
>
>
> function (\Acme\ProjectOne\Foo $foo) {} // Works as always
>
> function (\Acme\ProjectOne\Bar $bar) {} // Open question: allow or disallow 
> it?
>
> function (\Acme\ProjectOne\Baz $baz) {} // Open question: allow or disallow 
> it?
>
> ```
>
> This would allow public, private and protected classes in a way that I
> believe to be useful for the large ecosystem that surrounds Composer. From
> my extremely limited understanding of the engine, I think the easy/natural
> step would be to allow private/protected classes to be *received* outside
> its namespace because a type declaration does not trigger autoload.
> However, an important question is whether this is enough groundwork that
> could lead to optimizations that have been discussed when the topic of
> module is brought up. For instance, if type-hint outside the module is
> disallowed, could that make it easier to pack and optimize an entire module
> if we could instruct PHP how to load all symbols of a namespace all at
> once? I don't know.
> ------------------------
>
> As I'm writing this down I don't know if it could be related or if its
> something only making sense inside my head, but I see the above proposal
> paired with a potential amendment to PSR-4 (and Composer), to stimulate the
> community to pack small related symbols in a single file with an opt-in
> approach:
>
> composer.json:
> ```
> // ...
>
> "autoload": {
>     "psr-4-with-module": {
>         "App\\": "app/",
>     }
> },
>
> // ...
> ```
>
> ```
>
> <?php declare(strict_types=1);
>
> // app/Foo/Bar.php
> namespace App\Foo;
> class Bar {}
>
>
> // app/Foo.module.php
> namespace App\Foo;
> enum Baz {}
> enum Qux {}
>
>
> new \App\Foo\Bar; // loads app/Foo/Bar.php
> \App\Foo\Baz::option; // file app/Foo/Baz.php does not exist, tries 
> app/Foo.module.php before giving up
> \App\Foo\Qux::option; // app/Foo.module.php has been loaded and Qux has been 
> registered already
>
> ```
>
> Thoughts?
>
> --
> Marco Deleu
>


Hey all,

Anyone familiar with C++'s friend keyword? It’s not a direct replacement
for modules, but it solves similar problems — allowing trusted classes or
functions to access private/protected members without making them public.

The idea: allow one class to explicitly grant access to another class or
function. Useful for tightly coupled code that still wants to maintain
encapsulation. Since friend would be a new keyword, it’s safe to add
(currently a parse error).

Examples:
`
class Engine {
    private string $status = 'off';
    friend class Car;
    friend function debugEngine;
}

class Car {
    public function start(Engine $e) {
        $e->status = 'on'; // allowed
    }
}

function debugEngine(Engine $e) {
    echo $e->status; // also allowed
}
`
This avoids reflection, awkward internal APIs, or overly permissive
visibility. Could be useful in frameworks, testing tools, or any place
where selective trust is helpful.

Thoughts?

Hammed

>

Reply via email to