Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:124009 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 2224B1A009C for ; Sat, 29 Jun 2024 06:33:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1719642872; bh=eW1tRvlEcHz8cJVeuDYEw8MJKfCOXX1I/rX48mwZFe4=; h=References:In-Reply-To:From:Date:Subject:To:From; b=NJxoMmo9ZdL+l04/KqonJaJv47xAfjYSnVPP7Jy/RO7riiiUvn+X315jV6+o3nZqR urfvsKu87e3qalCLlVnbiQ+g0YokvCkyfQqLoLANe051lZ7Le6XaugnzRjzuYBU72m MEZCk0da/rOtje4A8LVPM3F7fyqJ2I9xofsGAXBt/bBieoQPxOyrjYH0DTsmr5BtQh wgF12T0HU8VlYJ+R+GssBVz/okFNsowYiJUEakq3tQJda1uFQICjLpzxekg2I34jye saT4aiXruo4UUqdyQXiYK/SkVL7/LwLCKCghE0vy635enXHQ4vfyB12z/OuicLqGQY AxjSv493PZCvg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 09A0A18005C for ; Sat, 29 Jun 2024 06:34:31 +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=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, 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 ; Sat, 29 Jun 2024 06:34:30 +0000 (UTC) Received: by mail-qv1-f47.google.com with SMTP id 6a1803df08f44-6b5834b3a94so10041556d6.2 for ; Fri, 28 Jun 2024 23:33:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719642790; x=1720247590; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=1/BKV9vkHvmaagdRTOhW/RDaq/minOpokR8gGptaVhk=; b=CrP1i8Nam8qeJujcwq4Mz528wUYBvlBNif5ukpV07abDd8ahStVmxkouwbmWAAUb2Q G4/o6tZShx0TwQXg8XwR22NGINW0p8z3Xdg6xIoylLCOdyZ6yKx2y1UmJ8dyP2eENjuV zQL/2D9tj2+Mg408o81TCTpm2BrtIZ/a+fu1vBNoNQKIm4EDc8s0td/CKQAi/MpGL49I UxMkdBE+ZlhfKGmmJDhx9sVxBKAzEYc69Q9iALLzqn+hCD7fSLeCWILYbXVfmtjSH9Zm IMpAW44F1wBg+veBkKfhhxULg/vondHMqLQ3wgJYvltHpnHO+biOINcmvMP9BosmFgRx EG1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719642790; x=1720247590; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=1/BKV9vkHvmaagdRTOhW/RDaq/minOpokR8gGptaVhk=; b=hNB7tvq2C86b/eRSIeiU2YRgf+iwLMTNJOivzOrUc3P0jNMd8p+eQJtHNgrWdyzEHM T2oQuwuDO/81/jlrxZb+U09LyXWo1/6iMVONyyNVYnA7ia79v9q+U08x9hTk9uuqKs1Z krueK7Yi1TP25gmTMhWNTLpgBPRiHXrTfoVPElGfkSGfV33sQc0OWxKycQ6Ea1PgcrDF u6P87540XXxSgWrg7EKnZ2CvKFfzOi1biu+SFZBJpwdxqqIC2054MuRkzOck9uUy/kBc Y3ZAW4BHDwEALvvR0bgkk1hpGNLCrMHU8KpeP6lq8j6/FdpBpFz+3sVTWbgolCSRP+cX +CBQ== X-Gm-Message-State: AOJu0YzYYQHr/q+DXJ5mssQsMnvdv/0cXm/5BCzSgLXlpukOKM2gJqUb xtrzlL676O3tgb9KEzLfPipyWv79Epdra/g1Zbd/few6Qh28v/udWqDIM1JC83yRNZoZWEmx+Z2 uUjYZZ8QpqdQ8QsIEfyHSlrZQ9i3z4Qd5 X-Google-Smtp-Source: AGHT+IFUE+6RDjREfOm+cd9K2/hjMHN4U9x9PBFtnzwKLPfEysg/CnOf5PCfGa/V4v3OsIwq8ItRAvL8urcm+0u5Ng8= X-Received: by 2002:a05:6214:dc1:b0:6b0:7eaf:febb with SMTP id 6a1803df08f44-6b5b713f773mr4644406d6.31.1719642789881; Fri, 28 Jun 2024 23:33:09 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: <1917CF7C-26D8-4DBE-B05C-5AA650AC6C9F@rwec.co.uk> <551cd5b0-1c00-4818-a9ca-97f6b7e8c3dc@app.fastmail.com> In-Reply-To: <551cd5b0-1c00-4818-a9ca-97f6b7e8c3dc@app.fastmail.com> Date: Sat, 29 Jun 2024 02:32:58 -0400 Message-ID: Subject: Re: [PHP-DEV] [Initial Feedback] PHP User Modules - An Adaptation of ES6 from JavaScript To: PHP internals Content-Type: multipart/alternative; boundary="000000000000a1b206061c01891a" From: tendoaki@gmail.com (Michael Morris) --000000000000a1b206061c01891a Content-Type: text/plain; charset="UTF-8" Not replying to anyone in particular and instead doing a mild reset taking into account the discussion that has gone before. So, I want to import a package. I'll create an index.php file at the root of my website and populate it with this. 'Hello {{ name }}' ]); $twig = new Environment($loader); export $twig; As mentioned in previous discussions, modules have their own variable scope. Back in our index we need to receive the variable render('index', ['name' => 'World']); If we load index.php in the web browser we should see "Hello World". If we look back in the mymodules folder we'll see the php.mod file has been updated namespace mymodule php 10.0 registry packagist.org/packages imports ( twig/twig v3.10.3 symfony/deprecation-contracts v2.5 //indirect symfony/polyfill-mbstring v1.3 //indirect symfony/polyfill-php80 v1.22 //indirect ) Note the automatically entered comment that marks the imported dependencies of twig. Meanwhile the php.sum file will also be updated with the checksums of these packages. So why this instead of composer? Well, a native implementation should be faster, but also it might be able to deal with php extensions. import "@php_mysqli" The @ marks that the extension is either a .so or .dll library, as I'll hazard a guess that the resolution mechanic will be radically different from the php language modules themselves - if it is possible at all. If it can be done it will make working with packages that require extensions a hell of a lot easier since it will no longer be necessary to monkey the php.ini file to include them. At a minimum the parser needs to know that the import will not be in the registry and instead it should look to the extensions directory, hence the lead @. Speaking of, having the extension directory location be a directive of php.mod makes sense here. Each module can have its own extension directory, but if this is kept within the project instead of globally then web SAPIs definitely need to stay out of those directories. Final thing to touch on is how the module namespaces behave. The export statement is used to call out what is leaving the module - everything else is private to that module. class A {} // private export class B {} // public All the files of the package effectively have the same starting namespace - whatever was declared in php.mod. So it isn't necessary to repeat the namespace on each file of the package. If a namespace is given, it will be a sub-namespace namespace tests; export function foo() {} Then in the importing file import "./src/mymodule" use \mymodule\tests\foo Notice here that if there is no from clause everything in the module grafts onto the symbol table. Subsequent file loads need only use the use statement. Exported variables however must be explicitly pulled because the variable symbol table isn't affected by namespaces (if I recall correctly, call me an idiot if I'm wrong). The from clause is useful for permanently aliasing - if something is imported under an alias it will remain under that alias. Continuing the prior example import tests\foo as boo from "./src/mymodule"; boo() That's enough to chew on I think. --000000000000a1b206061c01891a Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Not replying to anyone in particular and = instead doing a mild reset taking into account the discussion that=C2=A0has= gone before.=C2=A0

So, I want to impo= rt a package. I'll create an index.php file at the root of my website a= nd populate it with this.

<?php
import "= ;./src/mymodule";

Now I'll create that directory and run a command `php m= od init` in that directory. Stealing this from Go, it's fairly straight= forward though.=C2=A0 Now if we look in the directory we will see two files= .

php.mod
php.sum

The second file I'll not be to= uching on but exists to track checksums of downloaded packages - Composer d= oes the same with its composer-lock.json file which in turn was inspired=C2= =A0by node's package-lock.json.

The php.mod fi= le stands in for composer.json, but it isn't a json file.=C2=A0 It woul= d start something like this:

namespace mymodule
php 10.0

We start with three= directives - the root namespace is presumed to be the directory name. If t= hat isn't true this is a text file, change it.=C2=A0 PHP min version sh= ould be straightforward. Registry details where we are going to go get code= from.=C2=A0 Suppose we want to use our own registry but fallback to packag= ist.=C2=A0 That would be this:

namespace mymodule
php 10.0
r= egistry (
)
<= /div>
=C2=A0
Multiple registry entries will be checked for th= e code in order.=C2=A0 Handling auth tokens for restricted registries is ou= tside of scope at the moment.

So let's build t= he module. We'll make a file called hello.phm.=C2=A0 The reason for phm= and not php is so that web SAPIs will not try to parse this code.=C2=A0 Fu= rther they can be configured to not even allow direct https access to these= files at all.

import &qu= ot;twig/twig";
use \Twig\Loader\ArrayLoader;
use \Twig\Environment;
$loader =3D new ArrayL= oader([
=C2=A0 'index= ' =3D> 'Hello {{ name }}'
]);

$twig =3D new Environment($loader= );

=
= export $twig;

As mentioned in previous discussions, modules have their own varia= ble scope.=C2=A0 Back in our index we need to receive the variable

<?php
import $twig from "./src/mymodule"= ;

<= blockquote style=3D"margin:0px 0px 0px 40px;border:none;padding:0px">
<= font face=3D"monospace">$twig->render('index', ['name' = =3D> 'World']);

=C2= =A0If we load index.php in the web browser we should see "Hello World&= quot;.=C2=A0 If we look back in the mymodules folder we'll see the php.= mod file has been updated

namespace mymodule
php 10.0

imports (
=C2=A0 twig/twig v3.10.3
=C2=A0 symfony/deprecation-contracts v2.5 //indirect
=
=C2=A0 symfony/polyfill-mbstring v1.3 //indir= ect
=C2=A0 symfony/polyfi= ll-php80 v1.22 //indirect
)

Note the automatically entered c= omment that marks the imported dependencies of twig. Meanwhile the php.sum = file will also be updated with the checksums of these packages.
<= br>
So why this instead of composer?=C2=A0 Well, a native impleme= ntation should be faster, but also it might be able to deal with php extens= ions.

import "@= php_mysqli"

The=C2=A0@ m= arks that the extension is either a .so or .dll library, as I'll hazard= a guess that the resolution mechanic will be radically different from the = php language modules themselves - if it is possible at all. If it can be do= ne it will make working with packages that require extensions a hell of a l= ot easier since it will no longer be necessary to monkey the php.ini file t= o include them. At a minimum the parser needs to know that the import will = not be in the registry and instead it should look to the extensions directo= ry,=C2=A0hence the lead @. Speaking of, having the extension directory loca= tion be a directive of php.mod makes sense here.=C2=A0 Each module can have= its own extension directory, but if this is kept within the project instea= d of globally then web SAPIs definitely need to stay out of those directori= es.

Final thing to touch on is how the module name= spaces behave. The export statement is used to call out what is leaving the= module - everything else is private to that module.=C2=A0

class A {}=C2=A0 // private
export class B {}=C2=A0 // publi= c

All the files of the package ef= fectively have the same starting namespace - whatever was declared in php.m= od.=C2=A0 So it isn't necessary to repeat the namespace on each file of= the package. If a namespace is given, it will be a sub-namespace

namespace tests;=

exp= ort function foo() {}

Then in the importing file

import "./src/mymodule"
use \mymodule\t= ests\foo

<= blockquote style=3D"margin:0px 0px 0px 40px;border:none;padding:0px">
Notice here that if there is no from clause everything in the mo= dule grafts onto the symbol table.=C2=A0 Subsequent file loads need only us= e the use statement. Exported variables however must be explicitly pulled b= ecause the variable symbol table isn't affected by namespaces (if I rec= all correctly, call me an idiot if I'm wrong).

The from clause is useful for permanently aliasing - if something is impor= ted under an alias it will remain under that alias. Continuing the prior ex= ample

import tests\f= oo as boo from "./src/mymodule";

boo()

That's enough to chew on I think.
--000000000000a1b206061c01891a--