Re: [PHP-DEV] [RFC] [Discussion] Native Markup Expressions

[email protected] ("T.J. L")
Newsgroups php.internals
Message-ID <[email protected]>
Just came across this RFC. Given I've been maintaining XHP as a 
functioning PHP extension for years now (not sure if sending links in my 
very first internals message is going to flag something but it's 
TJ09/xhp-php-extension on github) I wanted to weigh in on the proposal 
here.

1.

 > Technically, markup must begin at a bare < in operand position, and 
telling that apart from the comparison and shift operators requires the 
scanner change described under Backward Incompatible Changes - state no 
extension can reach. The only route open to an extension is rewriting 
source text before compilation (the original XHP extension's approach), 
which shifts line numbers in errors and stack traces and leaves the raw 
file something token_get_all() - and therefore every tool built on it - 
cannot tokenize.

The extension takes care to avoid shifting line numbers; the 
preprocessed code ends up looking quite messy as a result but human 
readability was I think never the goal for what is functionally an 
intermediate representation.

 > Practically, a syntax lives or dies by its ecosystem. Code using an 
extension-only syntax cannot be reasonably published to Packagist - it 
is a parse error on any install without the extension - and no IDE, 
formatter, or static analyser updates its grammar for syntax that may 
not exist on a given machine. That chicken-and-egg is part of where XHP 
for PHP stalled, while the same feature thrived in Hack, where it is 
part of the language. Shipping in core is what makes markup part of PHP 
itself: parsers, IDEs, and analysis tools implement it once, and every 
developer's markup gets the same highlighting, formatting, and static 
analysis their ordinary code already enjoys.

This, though. This is the big thing. While it is *technically* possible 
for extensions to add new syntax, it is unreasonable to expect tools to 
be aware of that syntax. I can absolutely confirm that the biggest point 
of friction in using XHP today is the fact that static analysis tools 
like psalm or phpstan can't analyze files, code using XHP cannot be 
formatted or linted with php-cs-fixer, etc.

2.

One thing I think is missing that is commonly used in both my own XHP 
code but also various JSX frameworks is the idea of context. That is, 
the ability to pass data through parts of a tree without explicitly 
passing it through attributes. Factories/decorators may solve some of 
the need for this, but they seem to be global, so it doesn't seem 
possible to inject context into only a single subtree.

3.

 > This RFC is deliberately narrower than XHP: it targets HTML 
specifically, not general XML.

Does this mean that inline SVG is out of the question? It's not uncommon 
to embed SVG in HTML, but it does often rely on XML features...

-T.J. L

On 7/14/26 7:36 PM, Liam Hammett wrote:
> Hi internals,
>
> I'd like to open discussion on a new RFC, "Native Markup Expressions":
>
> RFC: https://wiki.php.net/rfc/native_markup_expressions
> Implementation (with tests): https://github.com/php/php-src/pull/22661
>
> It proposes a native syntax for HTML fragments as first-class PHP expressions,
> akin to how the frontend community has adopted JSX, with composition and
> escape-by-default output:
>
>
>      class Greeting implements Markup\Html
>      {
>          public function __construct(public string $name) {}
>
>          public function toHtml(): Markup\Html
>          {
>              return <>
>                  <h1 class="title">Hello, {$this->name}!</h1>
>                  <p>Welcome to PHP, where markup is a first-class
>                  expression.</p>
>              </>;
>          }
>      }
>
>      echo <Greeting name="Rasmus" />; // rendered HTML, values escaped
>
>
> Despite appearances, this is not a template language grafted onto the engine -
> the syntax is pure compile-time sugar. Every markup expression lowers
> during compilation to a plain `new` expression:
>
>
>      $html = <button class="btn">Sign in</button>;
>      // compiles to exactly:
>      $html = new \Markup\Element('button', ['class' => 'btn'], ['Sign in']);
>
>
> The RFC already answers many anticipated questions, and I am open
> to making further adjustments so this can become a feature the whole
> community benefits from.
>
> Looking forward to your feedback.
>
> Best regards,
> Liam
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.