Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123911 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 2A65C1A009C for ; Thu, 27 Jun 2024 02:16:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1719454639; bh=xfjEh/+WnfO8BEZh6CJ34z4DuoSfdxajH5KuHDhoUzI=; h=From:Date:Subject:To:From; b=kIEytCfhMv/K/f2BnFl0iMFWCj2eIuApS2VIy1z4RHt+pDTLxY7h1/LwEB9iMh5kc z3zVQKjNne1C6QoMg/mRineFRR0tc7WCufFBIhvncXz6f9wzRQ0vlR+3+lNA3RIsgw 08w7QQcPX7QdIE6P4jnM0mz9x5TaJP0lnG9/okK5Y9IO1Ec3Y1Ulmbpqxu0oEmLp9g b5oQS0s+IWJFYHcIeO55Pk399kizNjQkhP8yubJHCRAnonY0itAPFjTCPCgsf5+g1o J9mnbrN1pgT88PdlLSTElEUJN+lI9om9XfcF82aLqRNm1Pz2rgAVlcLSa2D8sU78DK PZPidO08IkpwQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 8F3FB1804F6 for ; Thu, 27 Jun 2024 02:17:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: * X-Spam-Status: No, score=1.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, FREEMAIL_REPLY,HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-qv1-f47.google.com (mail-qv1-f47.google.com [209.85.219.47]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 27 Jun 2024 02:17:18 +0000 (UTC) Received: by mail-qv1-f47.google.com with SMTP id 6a1803df08f44-6b4fc5c2f08so31306826d6.0 for ; Wed, 26 Jun 2024 19:16:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719454559; x=1720059359; darn=lists.php.net; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=rPVpsRHtYraAyAyTfe92pcmAHfgC0xKQ4LMNnKIMn2Q=; b=E54OM1ypd5DthNzHQ0OVNBo8b8DicYFztJ9XTxotkoGRHNimVGZ3EmcIdjaXrZ8eDx sh9/P7YonP7wkjtSEdK6sskuwO2tXYquJ3jRpYs3TRVTCgDIrtvgRzmd6oO5AcsGS71Q o3JNowiuhjy2HKXasSSSQCBC8rRkCZ8IQ8fu2s4OYpjJQD6taeZi2wcGekSz8+XC3Biy /HVIQx3NmdFNLyX3tW/IczOSeauoy9U9pFgSJEo6YTwFfsVm7fRHVy+tMiUngiQ7dX0Q ZJE8+WX5NDJYPnxPcmww7WJwXcMkWLk6p39IsuxLs+ZXid+XC6Xpqt0qyONKcJiICZhe wjZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719454559; x=1720059359; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=rPVpsRHtYraAyAyTfe92pcmAHfgC0xKQ4LMNnKIMn2Q=; b=XqNNtvIuu5m6vtxPbJT6Y8xUaD8+vAA86LCFqall0l5tEVzs0j5dyxhjxhFRLh+mwR 3JlU8Q0ym2duUNqGMu7t+e6tZVNb7+5A8DQsYUkZt+bGYfb03tqaifL+FIDZJ6OmRSb5 sTpNFrUsfwn6++CsmZFnasgCYH9SElwi6aDYxk6XzSj9mxwPPfDl3bECvxADtdCDO/qr 3DBq1MvJqvVaSg1rXVnDGG89bivddBOTzDjem9qfOzQ1vNewOi/UccRcOqPxxPymHSwR 76IeMaSZ0Z4Hqj/MT6TyBqAGx5G6L4AZgWuh9ewLQCpBDTQiTYJTDjM7JO6W9wUSiRHN SYEA== X-Gm-Message-State: AOJu0YxCrsns6ZnlP9EUUV9UVtes38J2lupE3JzEhJsrnoVguqQ12V/z hfNrdH4HRFjTsKiTCR5/epVk8ZSKHJlzlr/wn4ZDXJGnQU4IOm9r9m7sCGnRpKhU6D/i11OnD2W PbbmGtDsd75ASDT+iJYYvho4sokA2YUB8 X-Google-Smtp-Source: AGHT+IH4m4gmaYoFO7U9sD/X3mA4tVWy00XRjyK4aIma9DSOzMRbkVggZJ58E2Sex/jrybx46XBMavb4NsHSNpPeI5c= X-Received: by 2002:a05:6214:4b89:b0:6b2:b13c:5b12 with SMTP id 6a1803df08f44-6b53bff0228mr132669166d6.61.1719454558703; Wed, 26 Jun 2024 19:15:58 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 Date: Wed, 26 Jun 2024 22:15:47 -0400 Message-ID: Subject: [PHP-DEV] [Initial Feedback] PHP User Modules - An Adaptation of ES6 from JavaScript To: PHP internals Content-Type: multipart/alternative; boundary="0000000000002dd7ab061bd5b62f" From: tendoaki@gmail.com (Michael Morris) --0000000000002dd7ab061bd5b62f Content-Type: text/plain; charset="UTF-8" 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 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.michael@gmail.com. Is it possible to unsubscribe that email? --0000000000002dd7ab061bd5b62f Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
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&= #39;ve ran the thought experiment as far as I can on my own and want to sha= re 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 h= ave been passed over because of background compatibility. And then there is= the issue that PHP has multiple design flaws that seem impossible to get r= id of. Finally, I sense from conversations I've read that there are a l= ot of engine parser optimizations that haven't been tried because of th= e background compatibility problems present.

JavaS= cript was in this position as well 10 years ago when JavaScript modules wer= e introduced with the ES6 syntax. Only recently have these modules finally = begun to become first class members of node.js.=C2=A0 The existing CommonJS= require mechanism remains and will remain in Node for the foreseeable futu= re, but the ES6 syntax allows an opportunity to sidestep the issue. The mos= t significant=C2=A0of these is JavaScript modules run in strict mode, which= actually removes features that are problematic for the engine or make it d= ifficult to create optimized code.

Something simil= ar could be done in PHP, and that's what the remainder of this letter i= s 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 th= e Zend engine. In the text to follow I'm going to make wrong calls on s= ome things - maybe multiple things. I'm not married to anything here.= =C2=A0 Further, even if I were a master of the engine and knew where to sta= rt, 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 introdu= ction of three keywords: "import", "export" and "f= rom"

The PHP interpreter does not load PHP fi= les as modules unless it is directed to do so in an ini file or an .htacces= s file using the default_filetype directive.=C2=A0 If this directive is mis= sing its value will be "default" - the value "module" w= ill be used to trigger loading the initial PHP file as a module, and furthe= r types could in theory be introduced at a far later date.

Again, this setting only affects the INITIAL PHP script file loade= d by the interpreter, such as the index.php of Drupal. Files that are inclu= ded with include, include_once, require, or require_once will be imported a= s they always have.=C2=A0 Files that are included with import are PHP User = Modules.

User Module Files
PHP User Modu= les have the following properties (Proposed, and very much subject to chang= e):
* They are code files.=C2=A0 They have no <?php or ?> t= ags, and the inclusion of those tags is a=C2=A0parse 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 s= yntax would simplify the parser, then these too=C2=A0would be removed from = User Modules.
* They have no starting symbol table.=C2=A0 Each cl= ass, function or constant to be used must be imported with the import state= ment. Symbols declared in a user module do not affect the symbol tables of = the rest of the runtime.
* They have their own variable scope. Th= ey do not by default see globals or superglobals. Variables declared in a= =C2=A0module remain in that module. Superglobals can be imported (Ideally t= his is an opportunity to provide new more secure ways of accessing this dat= a as several userland libraries have done).
* They have no suppor= t for braceless syntax (which is only really useful when PHP is used as a t= emplate engine).
* User Modules run in strict mode.
* E= xceptions only. trigger_error will cause a parse exception.
* The= =C2=A0@ error suppression=C2=A0operator is not supported.
* Top l= evel return to stop parsing of the file early (as in include and require) i= s not supported.
* If at all possible, . as a connotation operato= r will not be supported and instead that operator will be used for scope re= solution instead of the three scope resolution operators currently in use f= or legacy reasons (::, -> and \ )
* Other language features wh= ose use is considered bad practice are also up for chopping.

=

Import Statement
PHP User modules are l= oaded by importing them, not by using include or require. It's syntax i= s similar to JavaScript's, but not exact - for one unlike JavaScript th= ere need not be a from clause.

User Modules can= 9;t use code that hasn't been imported to their symbol table.=C2=A0 So = if you want to use str_pos you need to import it

`= ``
import str_pos
```

An impor= t of a symbol will search for that symbol using the existing resolution rul= es, and if the symbol is not found the autoloaders are invoked. Once all ha= ve ran the import is retried and if the symbol now exists globally it can b= e imported.=C2=A0 This somewhat weird approach ensures that user modules ar= en't cut off from the existing ecosystem.

Why = not just require, or bother with importing existing symbols? My idea here i= s 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 easi= er 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.=C2=A0 That failed bec= ause it was too much to do in one pass.=C2=A0 Import allows language improv= ements to arrive piecemeal, and allows some of them to be userland. More on= that in a bit.

As with Javascript, aliasing is al= lowed.

```
import str_pos as strPos
```

The fun really starts when the from clau= se shows up.

```
import foo from "f= oo.php"
```

The search order of imp= ort is as follows:
1. Is the file in the same directory as the im= porting 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 lo= ok for a php_modules directory until at the cwd until the file is found (th= is is identical to the seek process of node with it's analogous node_mo= dules directory
4. As a final try, consider the PHP include_paths= .

This will of course require a package manager si= milar to composer to become part of core. However, composer will not be ecl= ipsed as the import package manager (phppm?) is only concerned with user mo= dules. 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 "mypa= ckage/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?=C2=A0 That is `import *`. To m= e this would mean "bring in the master symbol table"=C2=A0 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 impor= t will fail with an exception. Which brings us to...


Export statement

PHP User Module= s export code out using an export statement. If this didn't happen ther= e wouldn't be much point to them. Constants, classes and functions can = be exported.=C2=A0 Unlike JavaScript, there is no default export as there i= sn't an export object in the same sense as JavaScript.

```
export class Animal {}
export const pi =3D= 3.141527
export function foo {}
```

As in Javascript exports can be sourced with a from clause. This is = most frequently seen in packages.=C2=A0=C2=A0

= ```
export MyClass from "./MyClass.php"
expor= t * from "./methods.php"
```
The wildcard all= owing for all exports of another file to be exported at a common point, sim= plifying package interfaces.

Aliases are also poss= ible. For example, say you want to use multibyte string functions by defaul= t.=C2=A0 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"
```
<= div>
If you got this far, thank you. This overall idea to tak= e one of the better things to happen to JavaScript in the last decade and i= ncorporate it into PHP has been bothering me for awhile so I figured I'= d share.=C2=A0 I don't know how much merit there is to this though.

Note there's a lot more to JavaScript's imple= mentation of import and export that I only touched on here, but this letter= has gone on long enough for a surface level idea pitch.=C2=A0
Mod Note: It's been so long since I've sent any mail t= o the list that I'm getting mail from an address I no longer have acces= s to - dmgx.michael@gmail.com= .=C2=A0 Is it possible to unsubscribe that email?
--0000000000002dd7ab061bd5b62f--