[PHP-DEV] RFC: Single-Expression functions

Hi, Internals!

I hope this message finds you well. I would like to respectfully propose single-expression functions for PHP: https://wiki.php.net/rfc/single-expression-functions

I’ve had extensive experience working with Kotlin, which offers a modern approach to Java development and enables cleaner, more intuitive code. Through this experience, I’ve encountered various concise syntax features, and I believe one of them—single-expression functions—could be a valuable addition to PHP.

I’m aware that Larry Garfield previously proposed a similar feature several years ago, though it unfortunately didn’t pass the voting stage. I would like to respectfully suggest that using “=” instead of “=>” to separate declaration and implementation might be a better approach.

I believe this proposal aligns well with PHP’s current modernization efforts and the ongoing initiative to simplify various language constructs. PHP has been consistently improving developer experience through features like property promotion, arrow functions, the nullsafe operator, getters/setters, and other syntax enhancements. This single-expression function syntax would be a natural continuation of this trend, further streamlining the developer workflow and making PHP more pleasant to write.

The primary motivation is to help streamline “data classes” by eliminating the need for “{”, “return”, and “}”, which can sometimes account for up to 30% of the code in such classes. This improvement would be particularly timely as it directly enhances developer experience—a key focus of PHP’s recent evolution.

I would greatly appreciate your thoughts and feedback on this proposal, and I’m looking forward to engaging in constructive discussion with the community.

Thank you for your time and consideration.


Dmitriy Derepko

Hi Dmitriy

On 22/05/2025 12:24, Dmitry Derepko wrote:
> I'm aware that Larry Garfield previously proposed a similar feature
> several years ago, though it unfortunately didn't pass the voting stage.
> I would like to respectfully suggest that using "=" instead of "=>" to
> separate declaration and implementation might be a better approach.
That looks like the weakest part of the proposition because we already have two places where inline bodies are used: the mentioned arrow functions and property hooks

   public string $foo { get => 'dynamic value'; }

No sense in introducing a new syntax for basically just another case of inline function body.

> // oneline
> function handle(string $input): string = func1($input) |> func2(...) |> func3(...) |> func4(...);

That looks like a callable assignment like you know

   $f = fn ($bar) => $this->bar + $bar;

   class Foo {
       private $bar;

       public function bar() = $f;
   }

that may confuse users, another argument for =>

--
Anton

On Thu, May 22, 2025, at 8:53 PM, Anton Smirnov wrote:

Hi Dmitriy

On 22/05/2025 12:24, Dmitry Derepko wrote:
> I'm aware that Larry Garfield previously proposed a similar feature
> several years ago, though it unfortunately didn't pass the voting stage.
> I would like to respectfully suggest that using "=" instead of "=>" to
> separate declaration and implementation might be a better approach.

That looks like the weakest part of the proposition because we already
have two places where inline bodies are used: the mentioned arrow
functions and property hooks

   public string $foo { get => 'dynamic value'; }

No sense in introducing a new syntax for basically just another case of
inline function body.

> // oneline
> function handle(string $input): string = func1($input) |> func2(...)
|> func3(...) |> func4(...);

That looks like a callable assignment like you know

   $f = fn ($bar) => $this->bar + $bar;

   class Foo {
       private $bar;

       public function bar() = $f;
   }

that may confuse users, another argument for =>

--
Anton

Like Anton, I believe the arguments for using => and not = are strong, as detailed in the original RFC. Other than that, I am unsurprisingly in favor of short-function syntax.

If memory serves, the main argument against last time was "it doesn't actually do anything." It's purely sugar. Which is true, but IMO also not a fully compelling argument. Constructor promotion is purely sugar, but it absolutely makes life better. The short-hooks syntax is purely sugar, but makes life better. The question is whether the QoL improvement of the sugar justifies the engine complexity + conceptual complexity (for readers) that every feature comes with.

In this case, the engine complexity is not zero, but pretty close to it. The conceptual complexity is also low, especially if using =>. It is already established to mean "evaluates to", which is exactly what is described here. So the overall cost of this change would be quite low.

While the QoL benefit is not as large as it was for constructor promotion (which was huge), I do believe it is large enough to justify the fairly low cost. Especially as we integrate more and more expression-oriented features over time (pipes, null-safe methods, match(), throwable expressions, etc), which increases the surface area where the benefits will be felt.

--Larry Garfield

Thanks for your replies.

There is no big deal for me to use => instead of =. Just used to use =. I’ll change it then.

Thought there would be more thoughts against the RFC, but the voting will show these votes.
Could someone help me with the RFC process? Should I open the vote?


Dmitrii Derepko.
@xepozz

Hi

On 5/26/25 20:14, Dmitry Derepko wrote:

Could someone help me with the RFC process? Should I open the vote?

Please find PHP: rfc:howto for an explanation of the process.

An RFC needs *at least* two weeks of discussion, depending on the complexity of the RFC it should probably be longer to give everyone sufficient time to read the RFC and think it through.

Personally I did not yet have time to carefully read and understand the RFC to provide proper feedback.

Best regards
Tim Düsterhus

Hi Dmitry

Thanks for your interest in improving PHP.

On Thu, May 22, 2025 at 11:25 AM Dmitry Derepko <xepozzd@gmail.com> wrote:
>
> [https://wiki.php.net/rfc/single-expression-functions](https://wiki.php.net/rfc/single-expression-functions)

In the "Single-Expression functions in other languages" section, at least the Rust and Swift examples are wrong, as such a syntax does not exist for either of them. In case you got this info from an LLM, you should always fact-check whatever an AI tells you.

Ilija

On Mon, May 26, 2025, at 1:14 PM, Dmitry Derepko wrote:

Thanks for your replies.

There is no big deal for me to use `=>` instead of `=`. Just used to
use `=`. I’ll change it then.

Thought there would be more thoughts against the RFC, but the voting
will show these votes.
Could someone help me with the RFC process? Should I open the vote?

As Tim said, it needs at least a 2 week discussion period. It's also good practice to give it a few days after the last meaningful change, and announce an intent to open the vote a day or three in advance.

Did I miss it or did I not see a PR linked from the RFC? While technically having an implementation is not a prerequisite of an RFC, it is strongly recommended. (Also, having written the original patch, I'm curious if you're doing it the same way I did. It also may be sensible to use the compile step rather than strictly the lexer; moving pipes from strictly lexer to a compile step was a very smart move, for instance, as it simplified a lot of the ancillary behavior around debugging and error messages.)

--Larry Garfield

On May 26, 2025, at 11:05 PM, tovilo.ilija <tovilo.ilija@gmail.com> wrote:

In the "Single-Expression functions in other languages" section, at least the Rust and Swift examples are wrong, as such a syntax does not exist for either of them. In case you got this info from an LLM, you should always fact-check whatever an AI tells you.

Sure I did. Seems like I was confused by specifying a variable type along with the assigned value:

[

Documentation
docs.swift.org

favicon.ico

](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/#Using-Function-Types)

var mathFunction: (Int, Int) → Int = addTwoInts

I’ve double checked examples and removed Swift and Rust. Thanks for that.


Best regards,
Dmitrii Derepko.
@xepozz

As Tim said, it needs at least a 2 week discussion period.

Could you share the reference?

Did I miss it or did I not see a PR linked from the RFC? While technically having an implementation is not a prerequisite of an RFC, it is strongly recommended. (Also, having written the original patch, I’m curious if you’re doing it the same way I did. It also may be sensible to use the compile step rather than strictly the lexer; moving pipes from strictly lexer to a compile step was a very smart move, for instance, as it simplified a lot of the ancillary behavior around debugging and error messages.)

Here it is. I’ve added the link to the RFC.

It was one of my first PRs in PHP, so I did the things I only learned from there.
Lexer still should be adjusted to accept => syntax.


Best regards,
Dmitrii Derepko.
@xepozz

Hi

Am 2025-05-27 09:08, schrieb Dmitry Derepko:

As Tim said, it needs at least a 2 week discussion period.

Could you share the reference?

I already did in my email: PHP: rfc:howto (“When discussion ends, and a minimum period of two weeks has passed”).

Here it is. I've added the link to the RFC.

It took me a while to find the link in the “References” section, because that's not where I expected it based on other RFCs. Overall the RFC diverges from the RFC template quite a bit. As an example, the “RFC Impact” section is entirely missing. The “Voting Choices” section is as well. The “Metadata” section at the top is formatted differently for no reason (and still indicates that the RFC is a Draft). As far as I can tell it's also not listed in the RFC overview at PHP: rfc either.

As a first-time RFC author, I would recommend you strictly following the template and the “RFC How-To” to make sure that the RFC is complete and follows proper process.

Best regards
Tim Düsterhus

Thanks Tim for the answer.

Your replies went to the Spam folder. I don’t know why.

I’ll change the template as you suggested as soon as possible.

···

Dmitriy Derepko

I’ve changed the structure, followed the rfc template now.

The voting section isn’t available now, because the RFC is under discussion.

···

Dmitriy Derepko

Best regards,

Dmitrii Derepko.
@xepozz

Hi

Am 2025-05-22 11:24, schrieb Dmitry Derepko:

I hope this message finds you well. I would like to respectfully propose
single-expression functions for PHP:
PHP: rfc:single-expression-functions

Thank you for updating the RFC to match the template. I've read through it and have some comments:

1.

In the implementation I'm seeing that `$a = function() => 123;` will also become legal (“short closures with function instead of fn”). This is not mentioned in the RFC text. It also raises the question how that variant will interact with variable capturing.

2.

An AST printing test in the implementation would be useful to have. You can do that with `assert(false && new class { });` (using an anonymous class).

3.

I believe the reasoning given is not a fair comparison. The RFC says that `getName() "Name"` would be the relevant information, which I can agree with. But this is not what the proposed syntax looks like. A fair comparison would be:

     function getName() { return "Name"; }
     function getName() => "Name";

And when compared like this, it becomes clear that you are trading `{}` for `=>` and effectively only save the `return`, which to me provides little incremental value. Especially when comparing the signatures from the Calculator example:

     public function multiply(int $a, int $b): int => $a * $b;
     public function multiply(int $a, int $b): int { return $a * $b; }

I also don't like how the actual implementation is pushed to the right of the line. This makes it harder for me to scan for it. The linebreaks that the RFC states “create cognitive overhead” guide the eye for me. So perhaps we should also compare:

     public function multiply(int $a, int $b): int
         => $a * $b;
     public function multiply(int $a, int $b): int {
         return $a * $b;
     }

So basically the only thing we gain is the removal of a keyword in some situations. When trying to extend the logic in a function to more than one expression (which is not unlikely for methods), I would be forced to make multiple “boilerplate” changes instead of just adding my logic, effectively undoing any benefit the syntax might've provided.

Thus I'm very skeptical that the RFC provides sufficient value to justify the impact on the ecosystem (e.g. IDEs, static analyzers, documentation, confusion regarding another closure syntax, …).

Best regards
Tim Düsterhus