Re: [Pre-RFC] Pure-code source files via .phpc extension
| From: | Hendrik Mennen | Date: | Thu, 28 May 2026 04:02:50 +0000 |
| Subject: | Re: [Pre-RFC] Pure-code source files via .phpc extension | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131030@lists.php.net to get a copy of this message | ||
> Am 28.05.2026 um 04:31 schrieb Ben Ramsey <ramsey@php.net>:
>
> On 5/27/26 09:27, Hendrik Mennen wrote:
>>> Am 27.05.2026 um 15:19 schrieb Ben Ramsey <ramsey@php.net>:
>>>
>>> The problem with assigning meaning to a file extension is that the
>>> interpreter (currently) doesn't care what the file extension is. As long
>>> as it's text, it'll process any file and execute what comes after any
>>> <?php tags.
>> Right, that is the current behavior, and changing it is exactly what the proposal is about.
>> The engine would learn to check the file extension at the entry point (zend_compile_file for
>> SAPI/CLI, and the include/require family for nested loads) and use that to set the initial lexer
>> state. The .php behavior remains untouched.
>
>
> The behavior right now is that the file extension isn't checked. So, whether it's
> .php, .phtml, .php3, .rb, .py, or .txt doesn't matter. Using .php is a convention, not a
> requirement. If the proposal places any restrictions on the file extension, that's a major BC
> break.
>
> So, the logic will need to be something like: if .phpc, then parse assuming there are no
> <?php tags, otherwise assume there must be <?php tags.
>
>
>> That said, you point indirectly at something I do need to address: there are entry paths
>> where the engine does not have a filename, or has one it should not trust. Off the top of my head:
>> - stdin (cat foo.phpc | php). No filename available. Options: require an explicit CLI flag
>> (php --pure), or simply not support this path and document it.
>> - eval(). Operates on strings, not files. Extension is irrelevant here; eval() continues to
>> require <?php as today.
>> - Phar archives. Internal entries have filenames, so dispatch by extension should work, but
>> I would need to verify.
>> - include of a URL stream (rare, often disabled). Same question. Probably handled by
>> extension on the URL path.
>> I will work these out explicitly in the RFC draft. Thanks for surfacing it.
>>> At the risk of bike-shedding, I think it could be easy for others to
>>> confuse .phpc files as byte-code files, since it's common to see Python
>>> byte-code files with the .pyc extension.
>> Fair point, and one I had not weighed heavily enough. The Python .pyc parallel is real and
>> would cause exactly the kind of one-time confusion that adds friction to adoption. Boutell's
>> 2012 RFC used .phpp (Pure PHP) for the same purpose, which avoids the bytecode association. I am
>> open to .phpp or other suggestions; the disambiguator matters less than the mechanism.
>
>
> I'm still unsure about assigning any meaning to the extension. Maybe this is something
> that could be handled at the SAPI configuration level similar to how .phps files are configured?
> Likewise, maybe the CLI should have a
-p flag that tells it to
> process the input without checking for <?php tags.
>
> For what it's worth, php foo.phps still executes the file.
> You need to run php -s foo.phps to output HTML syntax-highlighted
> source. The ..phps extension has no meaning to the interpreter.
>
> That said, I'm not sure how you'd handle this with include/require or in Phar files.
>
>
> Cheers,
> Ben
Hi Ben,
> I'm still unsure about assigning any meaning to the extension. Maybe
> this is something that could be handled at the SAPI configuration
> level similar to how .phps files are configured?
Thanks, and also thanks for the correction on .phps. I had the wrong mental model there: I assumed
the extension carried interpreter meaning, when in fact it is purely an Apache handler convention
plus the php -s flag. Useful to have that straight before drafting.
That said, SAPI-level configuration is exactly the path I do not think can carry the full mechanism,
and I think your own observation at the end of your mail is the reason:
> That said, I'm not sure how you'd handle this with include/require or
> in Phar files.
Right, and this is the crux. include, require, and Phar entry resolution all happen below the SAPI
layer, inside the engine. A web server handler mapping .phpc to a pure-code mode would work for the
directly-served entry file, but the moment that file does require __DIR__ .
'/lib/something.phpc', the engine has to decide what to do with the included file on its
own, with no SAPI in the loop. The same applies to CLI: php script.php works through one path, php
-f script.php through another, both bypassing any web-server config. And Phar internals never see
SAPI at all.
So I think the dispatch has to live in the engine. The extension is just the most ergonomic signal I
can think of for the engine to use, but I am open to other engine-level signals (a magic first line,
a declare-like marker, even a per-Phar manifest flag). What I do not think works is delegating the
decision to layers above the engine, because those layers do not cover all entry paths.
> Likewise, maybe the CLI should have a -p flag that tells it to process
> the input without checking for <?php tags.
This I would take, as a complement rather than a replacement. The stdin case (cat foo | php) is
exactly where there is no filename to inspect, and a -p flag is a clean way to handle it. I will
include this in the draft as the explicit answer to the stdin entry path.
Would you find the proposal more palatable if the RFC framed the extension dispatch as one of
several engine-level signals (with the extension being the recommended default, but a declare-style
marker or a CLI flag covering the cases where extension is unavailable), rather than as the sole
mechanism? 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.
Hendrik Mennen
Maintainer, PHPolygon