Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:131033 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 8AB141A00BC for ; Thu, 28 May 2026 08:39:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1779957593; bh=0GxgqBAKsWuRdaE1TMaxRVi2pR8VrGoypr0kRK2nl+o=; h=From:Subject:Date:References:To:In-Reply-To:From; b=BXAatlorADayNF9ZGp4TC17slJk3CidM17CwMwgaDzBkImKeQREKIdb0h8+UbwACb YKZQyw0ySgNdxThc/ddVno6uJ4w9HjrKtqrrlEjPBCezkMayu7HWdsQvoGKyzdLPEk nfcXLNXmhagMyvsdIEsKvSzXNhmPfmkos9mNo7Iy7wE0qtZVi94r3EytkEMzFcXwQm r+1XOtHWebP0L90hHjeliYGhY02OROYX4wyO26mmQdZ177swgKeO9fN0XmiNn5A1ok Zid7Nhhiics8O6B4H8MFel5NDfUTTbDXPf/M4yNnzOK8ADU3KupdY1cbWQfTkpsJSf 4rVWarIiP8ctg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 0ECAF180057 for ; Thu, 28 May 2026 08:39:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.9 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS, FREEMAIL_ENVFROM_END_DIGIT,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.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) (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, 28 May 2026 08:39:51 +0000 (UTC) Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-45e7c636e74so6650153f8f.0 for ; Thu, 28 May 2026 01:39:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779957585; x=1780562385; darn=lists.php.net; h=message-id:in-reply-to:to:references:date:subject:mime-version:from :from:to:cc:subject:date:message-id:reply-to; bh=vP8WuA0wJ9q2rbvqVsxNkBz/IEM/PeIzO5+/9tHx4ek=; b=fuVHaG0XNUeuBZ3RHtxjSkl0bQhNgZvhAkuOx058mpERriEJVSdBHUf/0JJG4hFr5f xRX3LPPPEvZC/Uaxnk9g4qkm5ewKVWADgQrkF7vCbY79RxXgM9Hbgc/LlL+KvVj73Y4h IrolHdhcfFz+Ta3z+/fabjGZ3cKP3dtJ7DCQ2ZsNV4ZWDS6VekR4lMcnfrx0gxazW9ez WHblIuKKQtfQawFnFxuxWUJJsgsJp4LUZpx2nWh2dDRtEU7gFeC0+Lvt4jc67iRQU0IA Nsv5dUFstWJQvM60FbGi8f7XCL1XodbMaHnWSQ0spcLYeA9wGOtQj8RCM5HIIbGTBumZ rG4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779957585; x=1780562385; h=message-id:in-reply-to:to:references:date:subject:mime-version:from :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=vP8WuA0wJ9q2rbvqVsxNkBz/IEM/PeIzO5+/9tHx4ek=; b=RusJ9ckX47RZ+sG5n+YZ4VUIcLztPQNLIsx5gYDAIgQuVnq7/eym3KvxwMSQTwvm0f MVW+cDycKDyqX6mBTDfchygvyg2TAN4QIPHFfHWw0aZ3eoqY9tiEJnS7CZKuoymn1tAh 18igpaEEIUdiXcJnflscfgA+SbQD0nElWrkiU3g0M5XnWiv+/8Gezh1ovIgjEzXFWt6P XExkd1Lk4YnXmcH1W4jt/NphC0lAt2TT048ctMuVsjbS9UGtIe4vOZo3cwUhJOSP+VEX U//oryVsWGSx8MxEk3TAI2g949yW76NOkuLiP5BoKE7J4ql0qbRdxDOlTPVZwyTT6Mue di8A== X-Gm-Message-State: AOJu0YwULZ5k7T9UJSVaztvfeicmC2qGX/gHUO6kIIEZIUjI5C7j26C2 x0Hatunedcd06Q5JOzhTI8/q7Ym87Tcm85zK/fBltYG1Z4Zr6Ku/ym2HuUTNd5pT X-Gm-Gg: Acq92OHxNlVDsnaW5XyStf15VN2awAkvXAmzCP4gi1/891INUXm3qxx+5QAmscMKIv1 DDZ+TGHdHyOYoMuoxS+ONzalRFW6ZbJspDb4Mui9iCzOk4OhTE/6mkjlq8JTfdNjcRVMZCmF/2G YzTPVdARAVUWBWumyHvl1zlvLb4hPs2+mY/ANY7RJe0RLZbVpQoiuJgcEEljrppWi8f6bTjKEdg M9Z5upGqnfZx1F8cO+7PTpaU9ZgsCgufyf4d+NgHmn5bmdw+nVDqGhXVX1TP4KL9QjdiU2stEZe AkJIgUYD9TAfoCuqSGBA6OSIFC+tlxx2KPUQHNSL+RYggHdfKpPNzWF4uSmlm3GjP4WWVSewmtw me0Ko/rBn8FveHJnwmm6RcJVPE8iA3Vi0hkipGp4bJAZRGuOa/IQr7b/DIGIkDNTnW/vh8r/zVP ptb5qhKcfg/GYdfHXGowVor1pcemOYXZ/hAEMGVZgaVvrhAAN+zR2TOLKET6CBsI3j0CKFLVY16 ne57I8uDkDJQQ== X-Received: by 2002:a05:6000:468c:b0:45e:da9b:97d6 with SMTP id ffacd0b85a97d-45eda9b9842mr8935754f8f.27.1779957585359; Thu, 28 May 2026 01:39:45 -0700 (PDT) Received: from smtpclient.apple (p508ccfb8.dip0.t-ipconnect.de. [80.140.207.184]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45edb54a432sm17030683f8f.3.2026.05.28.01.39.44 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 28 May 2026 01:39:44 -0700 (PDT) Content-Type: multipart/alternative; boundary="Apple-Mail=_D8494FEC-9E0F-4B6C-8726-BDE8B52B8E97" Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: [PHP-DEV] [Pre-RFC] Pure-code source files via .phpc extension Date: Thu, 28 May 2026 10:39:33 +0200 References: <9E95EA03-B86A-D248-A980-B1E838F94C13@hxcore.ol> <20260527131921.086BB1A00BD@lists.php.net> <8AE9A269-2E40-42F0-A0F8-C6690B2935FE@gmail.com> <20260528023149.C97961A00BD@lists.php.net> <76D39851-7DAC-4F56-9615-B98B0A918770@gmail.com> <20260528043224.2CDD51A00BD@lists.php.net> <690e2bc4-d6c9-488b-bbd7-0010437f6c15@gmail.com> To: internals@lists.php.net In-Reply-To: <690e2bc4-d6c9-488b-bbd7-0010437f6c15@gmail.com> Message-ID: <878E83EF-DBA2-429A-A17B-55238600E834@gmail.com> X-Mailer: Apple Mail (2.3864.600.51.1.1) From: hmennen90@gmail.com (Hendrik Mennen) --Apple-Mail=_D8494FEC-9E0F-4B6C-8726-BDE8B52B8E97 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > Am 28.05.2026 um 08:36 schrieb Alex Rock : >=20 > Le 28/05/2026 =C3=A0 06:32, Ben Ramsey a =C3=A9crit : >> On 5/27/26 23:02, Hendrik Mennen wrote: >>>=20 >>> I am trying to understand whether your objection is to extension-=20 >>> based dispatch specifically, or to the broader idea of the engine=20 >>> making this decision at all.=20 >>>=20 >>=20 >> I don't have a strong objection to the engine making this decision, = but=20 >> I'd like to hear from others first.=20 >>=20 >> Cheers,=20 >> Ben=20 >=20 > I think this can be summarised with this: >=20 > File extension cannot have a "meaning" for the engine, as the engine = does not care about it at all in the first place > All SAPIs will consider a "normal PHP file" as default input, could it = be CLI, mod_php for Apache, or anything else (even FrankenPHP) > IMO this means that the default entrypoint for "parsing and executing = PHP files" for all SAPIs must not change, but might either be = complemented with a boolean arg for "pure PHP"/"no tags" , or = the engine must provide another public entrypoint for this that SAPIs = could implement or not. >=20 > An environment variable could be even used for that, and be included = in the engine by default, so that all existing SAPIs could be updated at = lower cost, but the variable name would have to be checked in all = existing Composer packages (something like "PHP_INPUT_PURE=3D0|1" , or = similar, TDB anyway), and would only be used for first included file. = Any subsequent call to "include/require" would still behave as before, = to avoid BC breaks. >=20 > And after that, to make use of this feature in userland projects, I = would suggest an "include_pure" (and its "require" + "_once" variants) = global keyword, to keep full compatibility everywhere. >=20 > WDYT? >=20 Hi Alex, Thanks for jumping in with concrete alternatives. Let me address each, = because I think the most important thing for the RFC draft is to be = precise about what the actual constraints are versus what is just the = current default. > * File extension cannot have a "meaning" for the engine, as the engine > does not care about it at all in the first place I would push back on this gently, because I think it is a description of = current behavior, not a constraint. The engine does have the filename = available in zend_compile_file and in the include/require resolution = path. Teaching it to check the extension there is a small, additive = change, not a violation of any architectural rule I am aware of. Other = languages do this routinely (Python differentiates .py from .pyc at the = loader level). So the question is not "can the engine know about = extensions" but "should we use that as the signal here." Happy to be = told there is an architectural reason I am missing, but if the objection = is just "this is not how PHP does it today," then the whole RFC is by = definition asking to change that. > * All SAPIs will consider a "normal PHP file" as default input, could > it be CLI, mod_php for Apache, or anything else (even FrankenPHP) Agreed, and nothing in the proposal changes that. Existing .php files = behave exactly as today through every SAPI. The proposal is additive: a = new file type that the engine handles differently, with zero impact on = the existing default path. > An environment variable could be even used for that, [...] and would > only be used for *first included file*. Any subsequent call to > "include/require" would still behave as before, to avoid BC breaks. This is where I see a real problem with the env-var approach. If only = the entry file is pure and everything it includes must be mixed-mode, = then pure code cannot be shipped as a library. A library author writing = pure code could never be loaded from a mixed-mode application, and vice = versa. The adoption story dies on contact with Composer. For pure-code files to be useful in practice, the parsing context has to = attach to the file itself, not to the entry-point execution. Otherwise = the feature is limited to a single bootstrap script, which is too narrow = to justify the engine change. > And after that, to make use of this feature in userland projects, I > would suggest an "include_pure" (and its "require" + "_once" variants) > global keyword This is essentially Tom Boutell's 2012 approach = (rfc/source_files_without_opening_tag), which used a modified include = syntax. Boutell ultimately abandoned that RFC, citing concerns that I = would summarize as: the caller decides how the file is parsed, not the = author. That inverts the usual relationship between a library and its = consumer. A library author cannot ship pure-code files with the = guarantee that they will be parsed as such, because consumers might = forget include_pure and load them with regular include. The same = physical file would parse differently depending on how it was loaded, = which is a discoverability and tooling nightmare. That said, I do not want to dismiss include_pure entirely. As a = complement to extension-based dispatch, it has merit: - For stdin and eval-like situations, where no filename exists, an = explicit per-call signal is exactly what is needed (Ben suggested php -p = for the CLI stdin case, similar idea). - For interop scenarios where someone wants to force pure-code parsing = on a file that does not have the extension, it provides an explicit = escape hatch. What I think does not work is replacing the extension-based mechanism = with include_pure, because then we lose the "file declares its own = parsing context" property. A possible synthesis: 1. Primary mechanism: file extension (the file itself declares its = parsing context, author-controlled). 2. CLI complement: -p flag for stdin (Ben's suggestion). 3. Userland complement: include_pure or similar for explicit override = (your suggestion, but as override not primary). This gives every entry path a clear answer and keeps author intent = intact. I will work this into the RFC draft. Does the engine-level dispatch via extension still feel wrong to you = once the alternative is framed this way, or is your objection more = specific to the .phpc letter than to the mechanism? Hendrik Mennen Maintainer, PHPolygon= --Apple-Mail=_D8494FEC-9E0F-4B6C-8726-BDE8B52B8E97 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8

Am 28.05.2026 um 08:36 schrieb Alex Rock = <pierstoval@gmail.com>:

=20 =20
Le 28/05/2026 =C3=A0 06:32, Ben = Ramsey a =C3=A9crit :
On 5/27/26 23:02, Hendrik Mennen wrote:

I am trying to understand whether your objection is to extension-
based dispatch specifically, or to the broader idea of the engine
making this decision at all.


I don't have a strong objection to the engine making this decision, but
I'd like to hear from others first.

Cheers,
Ben 


I think this can be summarised with this:

  • File extension cannot have a "meaning" for the engine, as the engine does not care about it at all in the first place
  • All SAPIs will consider a "normal PHP file" as default input, could it be CLI, mod_php for Apache, or anything else (even FrankenPHP)

IMO this means that the default entrypoint for "parsing and executing PHP files" for all SAPIs must not change, = but might either be complemented with a boolean arg for "pure PHP"/"no <?php ?> tags" , or the engine must provide another public entrypoint for this that SAPIs could implement or not.

An environment = variable could be even used for that, and be included in the engine by default, so that all existing SAPIs could be updated at lower cost, but the variable name would have to be checked in all existing Composer packages (something like "PHP_INPUT_PURE=3D0|1" , or similar, TDB anyway), and would only = be used for first included file. Any subsequent call to "include/require" would still behave as before, to avoid BC breaks.

And after that, to make use of this feature in = userland projects, I would suggest an "include_pure" (and its "require" + "_once" variants) global keyword, to keep full compatibility = everywhere.

WDYT?

Hi = Alex,

Thanks for jumping in with concrete = alternatives. Let me address each, because I think the most important = thing for the RFC draft is to be precise about what the actual = constraints are versus what is just the current = default.

> * File extension cannot have a = "meaning" for the engine, as the engine
>   does not = care about it at all in the first place

I would = push back on this gently, because I think it is a description of current = behavior, not a constraint. The engine does have the filename available = in zend_compile_file and in the include/require resolution path. = Teaching it to check the extension there is a small, additive change, = not a violation of any architectural rule I am aware of. Other languages = do this routinely (Python differentiates .py from .pyc at the loader = level). So the question is not "can the engine know about extensions" = but "should we use that as the signal here." Happy to be told there is = an architectural reason I am missing, but if the objection is just "this = is not how PHP does it today," then the whole RFC is by definition = asking to change that.

> * All SAPIs will = consider a "normal PHP file" as default input, could
> =   it be CLI, mod_php for Apache, or anything else (even = FrankenPHP)

Agreed, and nothing in the proposal = changes that. Existing .php files behave exactly as today through every = SAPI. The proposal is additive: a new file type that the engine handles = differently, with zero impact on the existing default = path.

> An environment variable could be = even used for that, [...] and would
> only be used for = *first included file*. Any subsequent call to
> = "include/require" would still behave as before, to avoid BC = breaks.

This is where I see a real problem with = the env-var approach. If only the entry file is pure and everything it = includes must be mixed-mode, then pure code cannot be shipped as a = library. A library author writing pure code could never be loaded from a = mixed-mode application, and vice versa. The adoption story dies on = contact with Composer.

For pure-code files to = be useful in practice, the parsing context has to attach to the file = itself, not to the entry-point execution. Otherwise the feature is = limited to a single bootstrap script, which is too narrow to justify the = engine change.

> And after that, to make use = of this feature in userland projects, I
> would suggest an = "include_pure" (and its "require" + "_once" variants)
> = global keyword

This is essentially Tom = Boutell's 2012 approach (rfc/source_files_without_opening_tag), which = used a modified include syntax. Boutell ultimately abandoned that RFC, = citing concerns that I would summarize as: the caller decides how the = file is parsed, not the author. That inverts the usual relationship = between a library and its consumer. A library author cannot ship = pure-code files with the guarantee that they will be parsed as such, = because consumers might forget include_pure and load them with regular = include. The same physical file would parse differently depending on how = it was loaded, which is a discoverability and tooling = nightmare.

That said, I do not want to dismiss = include_pure entirely. As a complement to extension-based dispatch, it = has merit:

- For stdin and eval-like = situations, where no filename exists, an explicit per-call signal is = exactly what is needed (Ben suggested php -p for the CLI stdin case, = similar idea).
- For interop scenarios where someone wants to = force pure-code parsing on a file that does not have the extension, it = provides an explicit escape hatch.

What I think = does not work is replacing the extension-based mechanism with = include_pure, because then we lose the "file declares its own parsing = context" property.

A possible = synthesis:

1. Primary mechanism: file extension = (the file itself declares its parsing context, = author-controlled).
2. CLI complement: -p flag for stdin = (Ben's suggestion).
3. Userland complement: include_pure or = similar for explicit override (your suggestion, but as override not = primary).

This gives every entry path a clear = answer and keeps author intent intact. I will work this into the RFC = draft.

Does the engine-level dispatch via = extension still feel wrong to you once the alternative is framed this = way, or is your objection more specific to the .phpc letter than to the = mechanism?

Hendrik Mennen
Maintainer, = PHPolygon
= --Apple-Mail=_D8494FEC-9E0F-4B6C-8726-BDE8B52B8E97--