PHP RFC: Pure-code source files via the ''.phpc'' extension
- Version: 0.4
- Date: 2026-06-16
- Author: Hendrik Mennen (hmennen) hmennen90@gmail.com
- Status: Under Discussion
- First Published at: http://wiki.php.net/rfc/optional_php_tags
- Pre-RFC discussion: https://news-web.php.net/php.internals/131024
- Target Version: PHP 8.6 / 9.0
Changelog
- 0.4 (2026-06-16) – Discussion-phase revision. Added two new “What this RFC does NOT claim” entries acknowledging Davey Shafik's points: (a)
.phpcis a categorical precedent shift (first PHP feature where filename extension drives lexer state at file-open time), and (b).phpcfiles lose the portable in-code “this is PHP” signal that<?phpprovides. Both costs are real, even if small. The RFC text was previously slightly over-leaning on “strictly additive” and “no downside” framings. - 0.3 (2026-06-16) – Discussion-phase revision. Rewrote the Motivation section to one core sentence plus a “What this RFC does NOT claim” subsection (per Kamil Tekiela's feedback that the original four-bullet motivation was diffuse). Added a new
Forward Compatibilitysection addressing the silent-text-emission risk when.phpcfiles are loaded by PHP versions that pre-date the RFC, including the Composer-mediated install-time mitigation (per Alex Rock's concern). Added aRejected Alternativesentry on bundling this RFC with a hypothetical JS-style strict mode (per Michael Morris's “one-shot opportunity” framing). Inline DokuWiki-escape fixes for__halt_compiler,__COMPILER_HALT_OFFSET__, andphar://so the wiki rendering no longer eats the underscores or italic-parses the double slash. The Examples section was simplified to avoid magic identifiers (__construct,__DIR__,__FILE__) that are eaten by some DokuWiki syntax-highlighter plugins inside<code>blocks; the test suite atZend/tests/phpc/continues to cover classes, magic constants, and the halt-compiler offset. - 0.2 (2026-06-15) – Initial publication. Pivoted from auto-detect on
.php(considered during pre-RFC drafting) to opt-in via.phpcextension, per pre-RFC consensus. - 0.1 (pre-RFC draft) – Internal draft, not published. Auto-detect on first byte of
.phpfiles. Rejected after pre-RFC discussion exposed BC concerns.
Introduction
PHP was born as a templating language. Every .php file is parsed in “inline content” mode and only enters scripting mode upon encountering an opening tag (<?php, <?=, or the long-deprecated <?). For files that ARE primarily PHP code – libraries, application classes, autoloader targets, CLI tools, framework internals – this is pure ceremony that hard-codes PHP's templating heritage into every file the language touches.
This RFC introduces a single, opt-in file extension – .phpc (“PHP code”) – whose semantics are: the file is pure PHP. The lexer enters ST_IN_SCRIPTING on the first byte of the file. The classic .php extension is completely unchanged: zero BC, zero behavior shift, zero risk to the templating use case PHP has always supported.
This was the approach the author proposed in the pre-RFC discussion (Mennen, 2026-05-27). The thread elicited substantive technical feedback – on SAPI vs. engine dispatch (Ben Ramsey), on alternative mechanisms (Alex Rock), on backward compatibility (Bruce Weirdan), and on security – which this document explicitly addresses below.
Motivation
The single core motivation:
Most new PHP files written today are pure code – framework classes, autoloaded library code, console commands, configuration files, route definitions. For these files the ''<?php'' opener carries no semantic information; it is a vestige of PHP's templating heritage that every file must repeat. PHP is the only modern mainstream language in which this prefix is mandatory.
.phpc is the smallest possible mechanism to remove that vestige for the files where it carries no meaning, without touching anything else.
What this RFC does NOT claim
To be explicit about what is NOT being argued:
- Not “the current model is broken”. PHP-as-templating works and will continue to work.
.phpfiles are unchanged. - Not “this is a big ergonomic win”. It is a small one. A reader who finds it negligible is not wrong.
- Not “additive features are automatically welcome”. “Strictly additive” is a necessary property of this RFC (anything that broke
.phpwould be DOA), not a motivation for accepting it. - Not “this is a free change with no downside”. It is a categorical shift: this would be the first PHP feature in which the filename's extension drives lexer state at file-open time.
.pharhas some filename-aware engine semantics via thephar://stream wrapper, but no precedent makes the lexer's starting state depend on the extension. Accepting this RFC means accepting that precedent. (Acknowledged in response to Davey Shafik, Discussion thread.) - Not “the in-code 'this is PHP' signal is irrelevant”. The
<?phpopener is a portable marker that travels with a code excerpt into Stack Overflow answers, blog posts, diff viewers, and IDEs that hide file extensions. A bare.phpcsnippet loses that signal until the reader knows what.phpcmeans. The cost is small (most snippets already drop<?phpfor brevity, context usually disambiguates) but it is not zero. (Acknowledged in response to Davey Shafik.)
Supporting considerations (not strong enough alone, but cumulative)
- CLI scripts. Today a CLI script reads
#!/usr/bin/env phpthen<?phpon the next line – a small hybrid header that no other#!-language requires. With.phpc, a script reads like Python, Ruby, or Node. - Engine-enforced file-mode signal.
.phtmlis a community convention for templates with no engine semantics..phpcwould carry an engine guarantee: a.phpcfile IS pure code – a property tools (IDEs, search, static analysis, code review) can rely on, not just assume. - Aesthetic alignment with the modern code-only majority of PHP. PHP looked different from other languages in the 1990s for good reasons. The templating shape no longer represents the median PHP file written in 2026.
Proposal
Detection rule
In Zend/zend_language_scanner.l::open_file_for_scanning, after the file buffer is loaded, the filename is checked. If it ends in the byte sequence .phpc (byte-exact memcmp, case-sensitive on all platforms in the reference implementation – see Open Issues for the case-folding discussion), the file is treated as pure-PHP:
- Skip a leading UTF-8 BOM (
0xEF 0xBB 0xBF), if present. - If CLI shebang skipping is enabled and the next two bytes are
#!, skip the entire shebang line up to and including the trailing\nand set the starting line to 2. - Enter
ST_IN_SCRIPTING. The lexer is now positioned to consume the first byte of code as PHP.
If the filename does not end in .phpc, the existing flow runs unchanged: BEGIN(SHEBANG) if CLI shebang skipping is active, otherwise BEGIN(INITIAL).
What is unchanged
Inside a .phpc file, the rest of the lexer is the same lexer that processes a .php file in ST_IN_SCRIPTING. Specifically:
?>continues to drop to inline output. A.phpcfile CAN trail with non-PHP content (rare but legal).__halt_compiler();continues to work and__COMPILER_HALT_OFFSET__is populated as today. This is verified in the test suite (Zend/tests/phpc/006_halt_compiler.phpt).- A literal
<?phpinside a.phpcfile is no longer a “tag” – it is parsed as code, which is a syntax error. Authors who accidentally double-open get a clear error, not silent text emission. <?=has no special meaning inside.phpc.
Examples
A .phpc library file (src/Greeter.phpc):
namespace App\Demo; function greet(string $who): string { return "hello, $who"; }
A CLI shebang script (bin/migrate.phpc):
#!/usr/bin/env php declare(strict_types=1); [$bin, $command] = $argv + [null, '--help']; echo "running: $command\n";
A classic app/bootstrap.php that requires a .phpc library:
<?php require 'src/greet.phpc'; echo App\Demo\greet('world');
(The examples above deliberately avoid magic identifiers like __construct and __DIR__ for clean rendering on wikis whose plugins process wiki markup inside <code> blocks. Full class definition and __halt_compiler() coverage is in the test suite at Zend/tests/phpc/ – tests 010 and 006 respectively.)
Why engine-level dispatch (response to Ben Ramsey)
Ben Ramsey raised the principled objection that “file extension cannot have meaning for the engine” and proposed SAPI-level handler configuration (web server mappings) plus a CLI -p flag for stdin as alternatives (php.internals/131026).
The author respectfully disagrees that SAPI configuration is sufficient, on technical grounds:
require/require_once/include/include_onceall execute inside the engine, viacompile_file()→open_file_for_scanning(). They do not consult the SAPI handler map. A web-server-only mapping would route the entry point but not the autoloaded.phpclibrary files it pulls in.- Phar archives likewise resolve internal entries through the engine. A Phar containing a mix of
.phptemplates and.phpclibrary files needs both formats to dispatch correctly without per-Phar configuration. - URL-stream includes (
include 'phar://app.phar/foo.phpc') are similarly engine-resolved. - The CLI
-pflag for stdin-as-pure-PHP is a genuinely good idea and is included below as a complementary feature, not a replacement.
Engine-level dispatch is the only mechanism that uniformly handles every code-loading path PHP supports. The extension check itself is a single memcmp on the filename's tail plus a few buffer-position adjustments – roughly 50 lines of straight-line C in open_file_for_scanning (a function that already runs once per compiled file). The runtime overhead is far below the cost of the surrounding I/O and lexer work; no benchmark numbers are claimed for it, on the basis that “constant-time tail compare on a string PHP has already loaded” needs no benchmarking.
Why not an environment variable / include_pure keyword / declare directive (response to Alex Rock)
Alex Rock suggested three alternatives in the pre-RFC thread (php.internals/131032):
PHP_INPUT_PURE=0|1environment variable, checked only for the first included file.- A new
include_pure/require_pure(plus_once) family of keywords. - A boolean argument to existing
include/require.
These are addressed in the Rejected Alternatives section below. The short version: each one shifts the decision about a file's parsing mode away from the file itself onto every caller of the file. .phpc keeps that decision where it belongs – with the file's author, encoded in its name, visible to every reader and tool, decoupled from how the file is loaded.
Backward Compatibility
The change is purely additive in the strictest sense: every byte sequence that compiled before this RFC compiles to the exact same op_array after this RFC, as long as the file extension is not .phpc. The full php-src test suite (Zend/, ext/tokenizer/, ext/standard/, ext/spl/, ext/reflection/, ext/phar/ – 9836 tests) passes with the reference implementation applied, with zero modifications to any pre-existing test.
The only theoretical BC concern, as Bruce Weirdan noted (php.internals/131038), is that “people could already be using files with that extension”. A .phpc file that contained template-style content (e.g., a file someone happens to have named page.phpc but that consists of HTML with embedded <?php blocks) would be reinterpreted as pure PHP.
Mitigating context:
.phpcis not a registered MIME type, not a documented PHP extension, not part of the PHP manual's accepted file-extension list, and not present in the default SAPI handler maps shipped by Apache (mod_php), nginx (sample fastcgi configs), Caddy, or FrankenPHP.- Composer's autoloader by default discovers
.phpfiles only; no major framework (Symfony, Laravel, CakePHP, CodeIgniter, Yii) lists.phpcas a recognised extension.
A small but real population of files using .phpc for unrelated purposes (custom build tooling, hand-rolled cache files, ad-hoc dev conventions) is to be expected on a language as old as PHP. The author has not conducted a comprehensive scan of public code corpora; an honest assessment is that the collision risk is small but not zero, comparable to any new file convention. The author requests that internals voters who have visibility into private codebases weigh in on this during the Discussion phase – an Open Issue below asks for community data points before the vote.
Forward Compatibility
Raised by Alex Rock in the Discussion thread: when a .phpc file is loaded by a PHP version that does not implement this RFC, the lexer enters its existing INITIAL state and emits the file contents as inline output. This is a worse failure mode than a plain syntax error, because in a web context it can silently expose source code.
This is real and worth flagging explicitly. The mitigations:
- Composer-mediated install-time enforcement (primary). A library shipping
.phpcfiles declares the target version in itscomposer.json:
{ "require": { "php": ">=8.6" } }
''composer install'' fails with a clear ''php'' version error on lower versions. The ''.phpc'' file never reaches an interpreter that does not understand it. This is the same mechanism every 8.x feature relies on (readonly classes, enums, property hooks); ''.phpc'' adds no new constraint. - **Application code is essentially unaffected.** Applications own the PHP version they deploy on; mismatches are a deployment error, not a language one. - **Shared libraries should adopt cautiously.** Library authors who want to support older PHP versions should NOT ship ''.phpc'' files yet, the same constraint that delayed widespread adoption of readonly classes, enums, etc. - **Non-Composer distribution** (manual ''git clone'', raw ''.zip'', vendored copies) bypasses install-time enforcement. The user assumes responsibility for matching PHP versions, identical to the situation for any 8.x feature.
The author has considered, and rejected, alternative mechanisms intended to make .phpc on an older interpreter fail hard rather than silently:
- A required canary header (e.g. mandatory
<?php die();as the first line). Rejected: defeats the entire point of.phpc(lexer starts inST_IN_SCRIPTING;<?phpinside.phpcis a syntax error per the RFC's own rules). - A magic byte sequence at file start. Rejected: ceremony, complicates tooling.
- A polyfill / compatibility shim for older PHP. Rejected: engine semantics are not poly-fillable in userland.
The honest position is that forward-compatibility for .phpc-using libraries is bounded by Composer's existing PHP-version enforcement and by responsible library-author discipline. Both mechanisms are in active use today.
Security
This RFC ships with security as a primary concern – not an afterthought – per the author's commitment in the pre-RFC discussion (php.internals/131035).
The risk
The risk is structurally identical to the historical .inc problem: a misconfigured web server serves a .phpc file as raw text, exposing PHP source code (and any secrets it contains) to anyone who requests the URL.
Required mitigations
This RFC ships with the following accompanying commitments:
- Documentation. The PHP manual entry for the feature must include canonical, copy-pasteable server configurations for Apache (
.htaccess+mod_php), Nginx (FastCGI), Caddy, and FrankenPHP that either route.phpcto the PHP handler or deny it. Reference snippets are included as Appendix A of this RFC. The author commits to authoring the manual section as part of landing. - Distro/packager outreach. The author commits to opening tracking issues with the major distro PHP packagers (Debian/Ubuntu, RHEL/Fedora, Homebrew, Laravel Herd, Docker Official
phpimages) to surface.phpcalongside.phpin their default configurations. - Composer coordination. A pre-landing PR or issue against
composer/composerto confirm that PSR-4 autoloading dispatches.phpcalongside.php. This is strongly desired but not a hard prerequisite for the language change to land – Composer can adopt asynchronously.
Recommended convention
.phpc files SHOULD live outside any web-served document root. The natural conventions follow what PSR-4-loaded code already does: src/, lib/, app/ – none of which are typically web-exposed. PHP CLI tools placed in bin/ are also outside document roots. The author recommends that frameworks (Symfony, Laravel, etc.) adopt .phpc as the default extension for newly-generated classes once stable, while leaving .php for explicit template files and public/ entry points.
RFC Impact
SAPIs
No code changes in any SAPI. The CLI shebang-skipping path (CG(skip_shebang)) is reused; the .phpc extension check is in the shared file-open path.
Existing Extensions
- ext/tokenizer.
token_get_all()/PhpToken::tokenize()operate on strings, not files. They are unaffected; their output for<?php echo 1;is identical before and after this RFC, and is asserted inZend/tests/phpc/012_token_get_all_unchanged.phpt. Direct file tokenization viatoken_get_all(file_get_contents(“foo.phpc”))still requires the caller to prepend<?php— a userland helper or a follow-up tokenizer flag (see Future Scope) would address that ergonomically, but is deliberately out of this RFC's scope. - ext/phar. Phar archives invoke the same
compile_file()code path with aphar://archive.phar/entryfilename. The.phpcextension check is byte-exact on the filename's tail, so a Phar entry namedlib.phpcis dispatched as pure-PHP exactly like a filesystem.phpcfile. This is the design intent; the reference implementation does not yet ship a dedicated Phar test (Phar test fixtures are heavyweight), but the code path is shared and a Phar test will be added during the Discussion phase if reviewers request it. - ext/opcache. OPcache caches post-compile op_arrays. They are identical to those produced by the classic path. Zero code change.
- ext/reflection. No surface changes.
Internal helpers
eval()usesZEND_COMPILE_POSITION_AFTER_OPEN_TAG(the string-compile path) and is unaffected: an eval'd snippet is already implicit-scripting, regardless of file extension.highlight_file()/show_source()tokenize files via the file-compile path. For.phpcfiles the output is expected to omit the leadingT_OPEN_TAGtoken, mirroring.phpc's actual token stream. Behaviour is by design, not code change; will be covered by a Discussion-phase test if reviewers request it.__halt_compiler()continues to work; the offset constant is populated from the lexer's position, which is unchanged.
php.ini Defaults
No new INI directives. (Notably, no global pure_php_files=on toggle – see Rejected Alternatives.)
Alternative extension names
The choice of .phpc is open for community feedback. Pre-RFC respondents flagged two friction points (php.internals/131027): a visual collision with Python's .pyc (bytecode files), and some scattered prior use of .phpc for unrelated tooling. The author considers .phpc the strongest semantic fit (“c” for “code”) but has committed to presenting alternatives in this section for voting:
.phpc– first choice, “code”.phpp– “pure” (note: this was the extension Boutell proposed in his 2012 RFC, which failed for unrelated reasons).pcode– descriptive but verbose.phpx– “executable”
The mechanism (extension-based engine-level dispatch) is independent of which letters the extension contains; this RFC's voting allows a separate sub-vote for the name.
Why this is different from prior failed RFCs
- Boutell 2012, “Source Files without Opening Tag” (https://wiki.php.net/rfc/source_files_without_opening_tag) – introduced a new
ASkeyword and required a per-include marker. Rejected primarily for syntactic overhead. This RFC: zero new syntax, zero per-include markers; dispatch is purely by filename. - Ohgaki 2014, “No-PHP-tags Mode” (https://wiki.php.net/rfc/nophptags) – proposed a
php.initoggle that flipped the mode for all files in the installation. Rejected because it produced two incompatible PHP dialects per server and broke template-engine cache files. This RFC: no global toggle;.phpcand.phpcoexist file-by-file.
Impact on template engines (Twig, Blade, Latte, Smarty, …)
None. All mainstream PHP template engines emit .php cache files prefixed with <?php as the first bytes. .phpc is opt-in by filename; no template engine, by default, writes .phpc files. Engines that wish to adopt .phpc for their compiled caches in the future may do so transparently; the engine code that invokes the cache is unaffected.
Open Issues
- Extension name (see above). Vote separately.
- Real-world
.phpcusage data. Author has not scanned public corpora; would welcome data points from internals voters with visibility into private/internal codebases on whether.phpcis in non-trivial use as a non-PHP file extension. - Case-sensitivity of the extension check. The reference implementation does a byte-exact
memcmpfor.phpc, soFoo.PHPCon a case-insensitive filesystem (Windows NTFS, default macOS APFS) would NOT be recognised. The alternative –zend_binary_strcasecmpfor the extension – would be more forgiving but introduces locale concerns. Strict byte-exact is the conservative default; this is open for discussion. - Composer coordination. Confirm with Composer maintainers that PSR-4 autoloader will dispatch
.phpcalongside.phpwith no user-side config required. (Strongly desired, not a hard prerequisite for the language change itself.) - OPcache file-key format. Verify that opcache's file cache key (path-based hash) treats
.phpcas distinct from.php(it does – the key is a path string – but worth confirming in code review).
Future Scope
- CLI
-p/--pureflag. Ben Ramsey's suggestion from the pre-RFC thread: a flag telling the CLI to treat its stdin (or the next file argument) as pure-PHP, equivalent to a.phpcfile. This is the natural way to pipe code without the ceremony ofecho “<?php …” | php. Deliberately separated from this RFC to keep scope tight; will be proposed as a follow-up RFC if this one passes. - Tokenizer flag for tag-less strings (working name
TOKEN_PARSE_PURE) so userland tools can tokenize tag-less code without manual<?phpprefixing. Follow-up RFC. - Framework adoption as the default for generated code (Symfony Maker, Laravel Artisan, etc.) – downstream, outside the language's scope.
- IDE / static-analyzer support. Major tools (PhpStorm, Psalm, PHPStan, PHP-CS-Fixer) recognise file modes by extension via their respective config files. Adding
.phpcshould be a small downstream change in each, but is not in this RFC's scope to coordinate; the author commits to opening tracking issues in each project on the day the RFC passes. - Webserver-config scanner / warning when
.phpcfiles appear inside an Apache/NginxDocumentRootwithout an explicit handler mapping. Belt-and-braces defence against the SOURCE-CODE-EXPOSURE failure mode discussed in the Security section.
Rejected Alternatives
- First-byte auto-detect on
.phpfiles (“if the file does not start with<, treat it as pure PHP”). Considered and prototyped – produces 0.08% test-suite BC hits in php-src, all in test fixtures – but the BC class is non-zero, and the principle that file extension is the carrier of file-format intent is cleaner. Rejected on BC grounds. PHP_INPUT_PURE=0|1environment variable (Alex Rock). Rejected: scope is wrong (the environment affects every PHP invocation in the process tree, but the property “this file is pure PHP” is per-file, not per-process). Also fails for FPM workers serving multiple requests.include_pure/require_purekeywords (Alex Rock). Rejected: forces the caller to know whether the callee is template-shaped or pure-shaped. The callee's nature should not propagate into everyrequiresite. PHP autoloaders would have to dispatch by inspecting the file before requiring it, defeating the purpose.declare(pure=1);first-statement marker. Rejected: still ceremony, and worse than<?phpbecause it must come AFTER an implicit<?php– chicken-and-egg.- Magic first line (e.g.
#!php) Rejected: indistinguishable from a real shebang to many tools, and invisible in the file extension where most tooling already configures behavior. - Global
php.initoggle. Rejected, see Ohgaki 2014. - SAPI-only handler mapping (Ben Ramsey). Rejected as insufficient, see “Why engine-level dispatch” above. The
-pCLI flag is adopted as complementary. - Bundle with a JavaScript-strict-mode-style language cleanup (Michael Morris). Rejected as a category error:
.phpcis about the file's parsing entry-point; a strict mode is about runtime semantics. The two are orthogonal axes - a future strict mode naturally lives indeclare()or an attribute, works in both.phpand.phpc, and consumes none of the design space.phpcuses. Bundling would force every.phpcadopter into strict mode whether they want it or not, and would extend Discussion/Voting by months while the strict-mode design is litigated. PHP already has multiple per-file opt-ins that landed individually (declare(strict_types=1),declare(ticks=1), readonly classes, enums); there is no scarce “one-shot” file-mode slot.
Proposed Voting Choices
Two simple yes/no votes (per language-change RFC convention, both requiring 2/3 majority):
- Primary vote: introduce
.phpcas an opt-in pure-PHP file extension as specified above. - Sub-vote (if primary passes): which extension name?
.phpc/.phpp/.pcode/.phpx– plurality wins.
Patches and Tests
- Implementation:
Zend/zend_language_scanner.l+53 / -2 in two functions: a ~50-line block inopen_file_for_scanningperforming the extension check, BOM/shebang skip, and state selection; plus a one-line use of the captured starting line number whereCG(zend_lineno)is reset. Regeneratedzend_language_scanner.c(built by re2c at compile time) is gitignored upstream and not part of the patch. - Tests:
Zend/tests/phpc/– 15 new.phpttests covering basic pure-PHP, the.php/.phpcBC sanity check, mixed require chains in both directions, UTF-8 BOM,__halt_compiler(), closing tag drop-out, empty files,declare(strict_types=1), namespaces+classes, eval() invariance,token_get_all()invariance, CLI shebang, literal<?phpas syntax error, and extension-match strictness (.phpcc/_phpc.phpmust NOT be matched). - Regression: full
Zend/,ext/tokenizer/,ext/standard/,ext/spl/,ext/reflection/,ext/phar/(9836 tests) – 0 failures, 0 modifications to pre-existing tests. - GitHub PR: https://github.com/php/php-src/pull/22315
Implementation
After this RFC is implemented, this section should contain:
- the version(s) it was merged into
- a link to the git commit(s)
- a link to the PHP manual entry for the feature
References
- Pre-RFC thread (May 2026): https://news-web.php.net/php.internals/131024
- Boutell 2012,
Source Files without Opening Tag: https://wiki.php.net/rfc/source_files_without_opening_tag - Ohgaki 2014,
No-PHP-tags Mode: https://wiki.php.net/rfc/nophptags - PSR-12 file format: https://www.php-fig.org/psr/psr-12/
- Zend lexer source:
Zend/zend_language_scanner.l
Appendix A — Canonical webserver configurations
Apache + mod_php
# In httpd.conf or .htaccess AddHandler application/x-httpd-php .phpc # OR, if you want .phpc never served: <FilesMatch "\.phpc$"> Require all denied </FilesMatch>
Nginx + PHP-FPM
location ~ \.phpc$ { fastcgi_pass unix:/run/php/php-fpm.sock; fastcgi_index index.phpc; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }
Caddy
php_fastcgi /path/to/php-fpm.sock {
try_files {path} {path}/index.phpc {path}/index.php =404
}
FrankenPHP
FrankenPHP builds on Caddy and inherits the same matcher syntax. The Caddy block above applies. For the embedded php_server shorthand, the file-extension filter is set indicatively as:
php_server {
# match .phpc alongside the default .php
file_extensions phpc php
}
The exact directive name should be confirmed against the FrankenPHP documentation for the target version when the manual entry is written; the principle (route .phpc alongside .php, or explicitly deny it) is the part this RFC asserts.