Re: Module or Class Visibility, Season 2

From: Date: Sun, 01 Jun 2025 05:26:24 +0000
Subject: Re: Module or Class Visibility, Season 2
References: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
Ok, the conversation is getting sidetracked, but I think some progress is
being made.

I started this latest iteration last year with a thread about introducing
something similar to the ES module system of JavaScript to PHP. What
attracts me to this particular model is that it should already be familiar
to the vast majority of PHP users. Prior to ES modules browsers had no
natural module import mechanic.  Prior to ES modules all symbols were
attached to the window. You can see this if you serve open this index.html
from a server (Note that opening the file locally will result in the js
being blocked by modern browser security. )

```html
<!DOCTYPE html>
<html>
  <head>
    <script>
      var a = 1234
    </script>
  </head>
  <body>
    <script>
      console.log(a)
      console.log(window.a)
    </script>
  </body>
</html>
```
The above spits 1234 into the console twice.  Second example - let's put a
module in.

```html
<!DOCTYPE html>
<html>
  <head>
    <script>
      var a = 1234
    </script>
    <script type="module">
      const a = 5678
      var b = 9123
    </script>
  </head>
  <body>
    <script>
      console.log(a)
      console.log(window.a)
      console.log(b)
    </script>
  </body>
</html>
```
This outputs 1234 twice and an error is raised about b being undefined.

I bring the above up to demonstrate that is the desired behavior of what I
originally called a PHP module and have been bullied over and taken to task
about not understanding the meaning of "module". Rowain seems to be more
comfortable characterizing this as containers. If everyone is happy with
that term I really don't care - I just want a way to isolate a code block
so that whatever happens in there stays in there unless I explicitly export
it out, and the only way I see things in that scope is if I bring them in.

The other thing that was done with ES is that the syntax for the modules
was tightened. JavaScripters cannot dictate what browser a user chooses, so
the bad decisions of the early days of JS never really went away until ES
came along which enforced their strict mode by default.  PHP has no such
strict mode - it has a strict types mode but that isn't the same thing.
There are multiple behaviors in PHP that can't go away because of backwards
compatibility problems, and one of those might indeed be how namespaces are
handled. In PHP a namespace is just a compile shortcut for resolving symbol
names. The namespace is prefixed to the start of every symbol within it.
Unlike Java or C#, PHP has no concept of namespace visibility. At the end
of the day it's a shortcut and its implementation happens entirely at
compile time.

Previously in the discussion Alwin Garside made a long but insightful post
on namespaces and their workings that I've been thinking on and trying to
digest for the last several days. What I've arrived at is the
discussions about composer and autoloaders are indeed a red herring to the
discussion. At the end of the day, PHP's include statements are a means to
separate the php process into multiple files. In his email he explored some
of the rewriting that could be done, and myself and Rowain have also
explored this in the form of namespace pathing and aliasing.

We've gotten away from the original focus of containing this code and how
that would work. So once again this moron is going to take a stab at it.

Container modules are created with require_module('file/path'). All code
that executes as a result of this call is isolated to its container. That
includes the results of any require or include calls made by the module
file itself or any file it requires.

Since the module file is cordoned off to its own container from the rest of
the application whatever namespaces it uses are irrelevant to outside code.
Any symbols created in the module will not be established in the script
that made the require_module() call. Since it is coming into being with a
new require mechanism it could be subjected to more efficient parsing rules
if that is desired, but that's a massive can of worms for later discussion.
One of those will be necessary - it will need to return something to the
php code that called it.  The simplest way to go about this is to just
require that it have a return. So...

$myModule = require_module('file/path');

or perhaps

const myModule = require_module('file/path');

The module probably should return a static class or class instance, but it
could return a closure.  In JavaScript the dynamic import() statement
returns a module object that is most similar to PHP's static classes, with
each export being a member or method of the module object.

Circling back to a question I know will be asked - what about autoloaders?
To which I answer, what about them? If the module wants to use an
autoloader it has to require one just as the initial php file that required
it had to have done at some point.  The container module is for all intents
and purposes its own php process that returns some interface to allow it to
talk to the process that spawned it.

Will this work? I think yes. Will it be efficient? Hell no. Can it be
optimized somehow? I don't know.


Thread (50 messages)

« previous php.internals (#127520) next »