Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127419 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 lists.php.net (Postfix) with ESMTPS id 1B9CE1A00BC for ; Wed, 21 May 2025 22:08:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1747865201; bh=6djQLE+H5uvww/+hsiHV28Dp0TVSyYjFoXVG2ax978k=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=BTgdnPzHE17dP0RE6F8yax7FX2cP1Lc7U99KpGsBobm55FMBo3kWBVGlzsLQwb1D8 oPvk6egrCt/Y30jOTkx/MaQvQDVlKXoAWGRzums5i6KJuuPAzJ/6notVLOpstSPsjG 4sAzhMqGSDc/O2sDKbLOh2U4de7tY9eQhpRiDy/mm/cIj53bYRwrRElV8SSgY73S7E +MUs3s2pDZDsCISERs5jCQzKbLDKEJFWREJnTFwEQsc+dPM3csvAvYEatuwuoYbB6c JSUUWw9bnvhFwqxcCca+r5tqTo2c7NVtZCgsO2oqVcrVVaKyRJRLgxOkE8FcFoRVYy K4WeuslB6/fTw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 46C8E1801D6 for ; Wed, 21 May 2025 22:06:40 +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 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-oa1-f43.google.com (mail-oa1-f43.google.com [209.85.160.43]) (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 ; Wed, 21 May 2025 22:06:40 +0000 (UTC) Received: by mail-oa1-f43.google.com with SMTP id 586e51a60fabf-2da14a6f89aso2331552fac.2 for ; Wed, 21 May 2025 15:08:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1747865328; x=1748470128; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=5upGL8wZvvZkDNdtx44VMgtzQHxNKAeJAH3WmHPzN1o=; b=XFj1TIqh2xePS0kiXyAllUNUsusUFy7KqfRYnAFz8SmrGJrqYQCByFApkT+yX4MobD TZUGyvSZBP+0m8OqLCnh2CMzNfPOsde7cDkOv7mNiwkObC3GcQ2I5R74JZjUghyIgz2V TZve5sBURu5o1KQ/pLO9RXVEsVTYXGYi0kFRQBpS7byo7JeE9WUHFRps8Lw5KT8gtdn3 46iq++eBDETFu8J3wQfcFg0d/MYB2cb1RUscK3hLMpTbPBDZFcpjIPYJWzLNeg5wI7jN okeo6BLnC2Z8xoF2IizCJLrKTwvvQg/9AophcsgUHNzGv5h/6Mg5mo6hGHMu9NuXYMTz 87RA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1747865328; x=1748470128; h=cc: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=5upGL8wZvvZkDNdtx44VMgtzQHxNKAeJAH3WmHPzN1o=; b=cbqZnO2ZCSgFeszy6HmVa4tUdtlACYj/zhXFY9da/jP/Jv6PNq9eIu4N0ybuBmqJVG 71cLkyl6KGnQbCKgGulI4kdIrvrUnrk+dlO4mvV5FbrwpJPj4F/5MQRmIU8Jk/gh+oTO 1OTFhp3sjcRz8Dfs4hks/H+7bFRvDAVNeg0Fsz5BvKNOxm7H0pa0FA+LAFB94Zj81TKF Yi3MywvJl1mSMcrPCB+VcovZ8fzmei/+EhP3v/2rtIQns9fwxtTpoUuPSlpWwtWp2dsp aCRzmF2WAD42Wmf9O2GfHmlUgNcDu0jak+/9ZhSJhuJFPR5S9ssXV9kE+6mNWRj46bGC AjKQ== X-Gm-Message-State: AOJu0YyeWR8teWpqetxuyDBXx8mRqoBv9J+ggOgvc1jz06FPIfUhCz92 ngHVaOuyzTcP4UqdkhzqGswQyVjgQjlPUoYc4m5Bqsqd/1Y7q4T/Qj+eHtIvA6FDaz0dTnbSQqt 6AMucmj22gqBvnF5E1CG7DToobP9tmHM= X-Gm-Gg: ASbGncvCmeoxdlbCCSSEkMEmlhZ1s6aLALrNsCz+gb80D0ZjWg5R/n4l5mWnMgfSRZ4 1ACKRFLpcW2ZLU0pZu0mTQyV67e+UaZU1nDdMZ0RkTEnFnGCpNpx1wLBwaLGqzlCFGddE8fpbEz 26q5el0i1p4IYfXYmN1O69R7fP9rvti49/Q5x0opzK6IIZ+YY0H2Y1Rxf0J/QiFLwwww== X-Google-Smtp-Source: AGHT+IHqAtUvUR0o89KeOjNOk2MwO4xbPnvx1Z/rhPHCZqR2gxCQ5nWWicLi7U5DC4/vyvFnSW/lJMWty40Ma3E0RXE= X-Received: by 2002:a05:6871:215:b0:2c7:6f57:3645 with SMTP id 586e51a60fabf-2e3c1c9ba0dmr12808891fac.18.1747865327822; Wed, 21 May 2025 15:08:47 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Wed, 21 May 2025 16:08:30 -0600 X-Gm-Features: AX0GCFvVJxRI8TnSrX2zvYjMS_4So3jiEFGc42eQzqE3CJstB1Vy3cHvLyc4pJo Message-ID: Subject: Re: [PHP-DEV] Module or Class Visibility, Season 2 To: Deleu Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000faec860635ac9bee" From: hamiegold@gmail.com (Hammed Ajao) --000000000000faec860635ac9bee Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, May 13, 2025, 9:32=E2=80=AFa.m. Deleu 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 conversati= on > 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 tha= t > 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 > > > 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 inst= antiate 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 inst= antiate private class \Acme\ProjectOne\Bar from \Corp\Corp > > new \Acme\ProjectOne\Baz; // Fatal error: Uncaught Error: Cannot inst= antiate 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 disall= ow it? > > function (\Acme\ProjectOne\Baz $baz) {} // Open question: allow or disall= ow 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. Fro= m > my extremely limited understanding of the engine, I think the easy/natura= l > 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 modu= le > 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 t= he > community to pack small related symbols in a single file with an opt-in > approach: > > composer.json: > ``` > // ... > > "autoload": { > "psr-4-with-module": { > "App\\": "app/", > } > }, > > // ... > ``` > > ``` > > > // 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/F= oo.module.php before giving up > \App\Foo\Qux::option; // app/Foo.module.php has been loaded and Qux has b= een registered already > > ``` > > Thoughts? > > -- > Marco Deleu > Hey all, Anyone familiar with C++'s friend keyword? It=E2=80=99s not a direct replac= ement for modules, but it solves similar problems =E2=80=94 allowing trusted clas= ses 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=E2=80=99s safe to ad= d (currently a parse error). Examples: ` class Engine { private string $status =3D 'off'; friend class Car; friend function debugEngine; } class Car { public function start(Engine $e) { $e->status =3D '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 > --000000000000faec860635ac9bee Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


On Tue, May 13, 2025, 9:32=E2=80= =AFa.m. Deleu <deleugyn@gmail.com<= /a>> wrote:




=
=
<?php declare(strict_types=3D1);

namespace Acme<= /span>\ProjectOne
{
public class
Foo {} // same as class Foo {}

private class = Bar {} // only visible inside Acme\ProjectOne<= br>
protected class
Baz {} // visible inside Acme
}

namespace Acme\<= span style=3D"color:rgb(0,0,0)">ProjectTwo
{
new = \Acme\ProjectOne\Foo; // Work as always

new \Acme\ProjectOne\Bar; // Fatal error: Uncaugh= t Error: Cannot instantiate private class \Acme\ProjectOne\Bar from \Acme\P= rojectTwo

<= /span>new \Acme\ProjectOne\B= az; // Work= s
}

namespace <= span style=3D"color:rgb(0,0,0)">Corp
\Corp
{
new \Acme\ProjectOne\Foo; // Work as always

new <= span style=3D"color:rgb(128,128,128)">\Acme\ProjectOne\Bar; // Fatal error: Uncaught Error: Cannot instantiate private = class \Acme\ProjectOne\Bar from \Corp\Corp

= new \Acme\ProjectOne\<= span style=3D"color:rgb(0,0,0)">Baz; // Fatal error: Uncaught Error: Cannot instantiat= e protected class \Acme\ProjectOne\Baz from \Corp\Corp
}

<= br>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 d= isallow it?



<= div dir=3D"auto">

Examples:
`
class Engine {
=C2=A0 =C2= =A0 private string $status =3D 'off';
=C2=A0= =C2=A0 friend class Car;
=C2=A0 =C2=A0 friend funct= ion debugEngine;
}

=
class Car {
=C2=A0 =C2=A0 public f= unction start(Engine $e) {
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 $e->status =3D 'on'; // allowed
=C2= =A0 =C2=A0 }
}

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

Thoughts?

Hammed
--000000000000faec860635ac9bee--