Hello all. This is a ramble of an idea that's managed to run around my head for a few days now. It isn't fully formed, but I've ran the thought experiment as far as I can on my own and want to share it with all of you.
I've mostly been a lurker and I've seen a lot of RFC's come and go. Of those not accepted many have been passed over because of background compatibility. And then there is the issue that PHP has multiple design flaws that seem impossible to get rid of. Finally, I sense from conversations I've read that there are a lot of engine parser optimizations that haven't been tried because of the background compatibility problems present. JavaScript was in this position as well 10 years ago when JavaScript modules were introduced with the ES6 syntax. Only recently have these modules finally begun to become first class members of node.js. The existing CommonJS require mechanism remains and will remain in Node for the foreseeable future, but the ES6 syntax allows an opportunity to sidestep the issue. The most significant of these is JavaScript modules run in strict mode, which actually removes features that are problematic for the engine or make it difficult to create optimized code. Something similar could be done in PHP, and that's what the remainder of this letter is about, but before I continue I want to make clear my vantage point: I am but a humble user of the code, I'm no expert on the underpinnings of the Zend engine. In the text to follow I'm going to make wrong calls on some things - maybe multiple things. I'm not married to anything here. Further, even if I were a master of the engine and knew where to start, the scope of this is too large for any one person to undertake. So all that said, I'll begin. PHP User Modules are php files that are brought into the runtime through a new parser that is able to generate faster and more concise runtime code by removing support for problematic features and imposing a strict mode by default. They focus on PHP as a language and not as a template engine. The only background compatibility break is the introduction of three keywords: "import", "export" and "from" The PHP interpreter does not load PHP files as modules unless it is directed to do so in an ini file or an .htaccess file using the default_filetype directive. If this directive is missing its value will be "default" - the value "module" will be used to trigger loading the initial PHP file as a module, and further types could in theory be introduced at a far later date. Again, this setting only affects the INITIAL PHP script file loaded by the interpreter, such as the index.php of Drupal. Files that are included with include, include_once, require, or require_once will be imported as they always have. Files that are included with import are PHP User Modules. User Module Files PHP User Modules have the following properties (Proposed, and very much subject to change): * They are code files. They have no <?php or ?> tags, and the inclusion of those tags is a parse exception. I know this will be problematic for PHP storm and other IDE's, but it's not an insurmountable problem. * If the removal of HEREDOC and NOWDOC syntax would simplify the parser, then these too would be removed from User Modules. * They have no starting symbol table. Each class, function or constant to be used must be imported with the import statement. Symbols declared in a user module do not affect the symbol tables of the rest of the runtime. * They have their own variable scope. They do not by default see globals or superglobals. Variables declared in a module remain in that module. Superglobals can be imported (Ideally this is an opportunity to provide new more secure ways of accessing this data as several userland libraries have done). * They have no support for braceless syntax (which is only really useful when PHP is used as a template engine). * User Modules run in strict mode. * Exceptions only. trigger_error will cause a parse exception. * The @ error suppression operator is not supported. * Top level return to stop parsing of the file early (as in include and require) is not supported. * If at all possible, . as a connotation operator will not be supported and instead that operator will be used for scope resolution instead of the three scope resolution operators currently in use for legacy reasons (::, -> and \ ) * Other language features whose use is considered bad practice are also up for chopping. Import Statement PHP User modules are loaded by importing them, not by using include or require. It's syntax is similar to JavaScript's, but not exact - for one unlike JavaScript there need not be a from clause. User Modules can't use code that hasn't been imported to their symbol table. So if you want to use str_pos you need to import it ``` import str_pos ``` An import of a symbol will search for that symbol using the existing resolution rules, and if the symbol is not found the autoloaders are invoked. Once all have ran the import is retried and if the symbol now exists globally it can be imported. This somewhat weird approach ensures that user modules aren't cut off from the existing ecosystem. Why not just require, or bother with importing existing symbols? My idea here is clarity. It should be easier on the IDE's and probably on the parser if these are called out. Also, explicitly importing functions makes it easier to get to fixed versions, which is a repeated stumbling block of many an RFC. I hereby invoke the ghost of PHP 6 and unicode. That failed because it was too much to do in one pass. Import allows language improvements to arrive piecemeal, and allows some of them to be userland. More on that in a bit. As with Javascript, aliasing is allowed. ``` import str_pos as strPos ``` The fun really starts when the from clause shows up. ``` import foo from "foo.php" ``` The search order of import is as follows: 1. Is the file in the same directory as the importing file? Yes, load. 2. Is there a php_modules directory? If so, is the file in there? 3. If the importing file is within the tree of the cwd (established by the first file loaded), then recursively look for a php_modules directory until at the cwd until the file is found (this is identical to the seek process of node with it's analogous node_modules directory 4. As a final try, consider the PHP include_paths. This will of course require a package manager similar to composer to become part of core. However, composer will not be eclipsed as the import package manager (phppm?) is only concerned with user modules. These modules must explicitly export any symbols being fetched from them, whereas composer will continue to load files using require. Imports can also be done against directories ``` import foo from "mypackage" ``` In this case the parser will look for "mypackage/index.php" All exports of a file can be brought in with a wildcard ``` import * from "file.php" ``` Should a wildcard be allowed without the from clause? That is `import *`. To me this would mean "bring in the master symbol table" I'm not sure if that's a good idea as it feels like a bad practice. Also note, if foo.php doesn't export foo, the import will fail with an exception. Which brings us to... Export statement PHP User Modules export code out using an export statement. If this didn't happen there wouldn't be much point to them. Constants, classes and functions can be exported. Unlike JavaScript, there is no default export as there isn't an export object in the same sense as JavaScript. ``` export class Animal {} export const pi = 3.141527 export function foo {} ``` As in Javascript exports can be sourced with a from clause. This is most frequently seen in packages. ``` export MyClass from "./MyClass.php" export * from "./methods.php" ``` The wildcard allowing for all exports of another file to be exported at a common point, simplifying package interfaces. Aliases are also possible. For example, say you want to use multibyte string functions by default. You can do this in one file now ``` export mb_str_pad as strPad; export mb_str_split as strSplit; ``` And so on, then import ``` import * from "myMbAliases.php" ``` If you got this far, thank you. This overall idea to take one of the better things to happen to JavaScript in the last decade and incorporate it into PHP has been bothering me for awhile so I figured I'd share. I don't know how much merit there is to this though. Note there's a lot more to JavaScript's implementation of import and export that I only touched on here, but this letter has gone on long enough for a surface level idea pitch. Mod Note: It's been so long since I've sent any mail to the list that I'm getting mail from an address I no longer have access to - dmgx.mich...@gmail.com. Is it possible to unsubscribe that email?