[PHP-DEV] Discussion Short Constructor

Hi,

I’ve found a discussion about Records https://externals.io/message/125975 and found a one key point which I really like in Kotlin (hello): short constructors.

Rob said that short constructor will be probably removed:

  1. Inline constructor isn’t necessary and could be proposed separately. I’ve thought recently about this feature

I will probably remove this, to be honest. It was for nesting records inside classes or other records, but this feature was declined, so there isn’t really a need for it.

Whether it’s true or not I’ve played with syntax analyser and created a sugared polyfill for short constructors: https://github.com/php/php-src/pull/19133

Many examples of how it works inside the PR, just read them.

Should I propose the RFC or not?

This step move us further to “light” structures or “heavy” structures written “simple”:

class RedBox extends Box(width: 50, height: 200);

$box = new RedBox();

instead of

class RedBox extends Box {
public function __construct()
{
parent::__construct(width: 50, height: 200);
}
}

OR

class RedBox extends Box {
public function getWidth(): int
{
return 50;
}

public function getHeight(): int
{
return 200;
}
}

OR even with Single Expression Functions RFC:

class RedBox extends Box {
public function getWidth(): int => 50;

public function getHeight(): int => 200;
}

···

Best regards,

Dmitrii Derepko.
@xepozz

On Tue, Jul 15, 2025, at 1:07 PM, Dmitry Derepko wrote:

Hi,

I've found a discussion about Records
RFC: Records - Externals and found a one key point which I
really like in Kotlin (hello): short constructors.

Rob said that short constructor will be probably removed:

1. Inline constructor isn’t necessary and could be proposed separately. I’ve thought recently about this feature

I will probably remove this, to be honest. It was for nesting records
inside classes or other records, but this feature was declined, so
there isn't really a need for it.

Whether it's true or not I've played with syntax analyser and created a
sugared polyfill for short constructors:
[draft] short constructor by xepozz · Pull Request #19133 · php/php-src · GitHub

Many examples of how it works inside the PR, just read them.

Should I propose the RFC or not?

This step move us further to "light" structures or "heavy" structures
written "simple":

class RedBox extends Box(width: 50, height: 200);

$box = new RedBox();

instead of

class RedBox extends Box {
    public function __construct()
    {
        parent::__construct(width: 50, height: 200);
    }
}

OR

class RedBox extends Box {
    public function getWidth(): int
    {
        return 50;
    }

    public function getHeight(): int
    {
        return 200;
    }
}

OR even with Single Expression Functions RFC:

class RedBox extends Box {
    public function getWidth(): int => 50;

    public function getHeight(): int => 200;
}

--
Best regards,
Dmitrii Derepko.
@xepozz

I have some concerns that there may be edge cases we've not thought about, but at the moment I am generally in favor. An RFC and implementation would likely help ferret out those edge cases.

I agree that this combined with single expression functions would go a long way to making lightweight data structures even easier to create and use.

--Larry Garfield

On Tue, Jul 15, 2025, at 20:07, Dmitry Derepko wrote:

Hi,

I’ve found a discussion about Records https://externals.io/message/125975 and found a one key point which I really like in Kotlin (hello): short constructors.

Rob said that short constructor will be probably removed:

  1. Inline constructor isn’t necessary and could be proposed separately. I’ve thought recently about this feature

I will probably remove this, to be honest. It was for nesting records inside classes or other records, but this feature was declined, so there isn’t really a need for it.

Whether it’s true or not I’ve played with syntax analyser and created a sugared polyfill for short constructors: https://github.com/php/php-src/pull/19133

Many examples of how it works inside the PR, just read them.

Should I propose the RFC or not?

This step move us further to “light” structures or “heavy” structures written “simple”:

class RedBox extends Box(width: 50, height: 200);

$box = new RedBox();

instead of

class RedBox extends Box {
public function __construct()
{
parent::__construct(width: 50, height: 200);
}
}

OR

class RedBox extends Box {

public function getWidth(): int
{
return 50;
}

public function getHeight(): int

{
return 200;
}
}

OR even with Single Expression Functions RFC:

class RedBox extends Box {

public function getWidth(): int => 50;

public function getHeight(): int => 200;

}

Best regards,

Dmitrii Derepko.
@xepozz

Hi Dmitrii,

I meant that I’d remove it from the records RFC, not that I wouldn’t ever pick it up. In fact, I put it on my todo list and announced it to this list, 7 months ago: https://externals.io/message/125975#126029

Fun fact: it was a part of my original proposal with nested classes that then got removed due to feedback.

Why I haven’t proposed it as a separate RFC: with PSR-4 being so popular, nobody is going to write one-line files to take advantage of this. Thus, when I was going to revisit nested classes later this year (after all the release shenanigans and some personal issues), I was planning to add this feature to the nested class v2 RFC (again). A lot of feedback I got on nested classes was “when would I use this?” – and I suspect that would be a lot of the feedback you’d get here (see: PSR-4). I’m more convinced than ever that short constructors and nested classes create a chicken-and-egg problem. They only really make sense together; at least with our current coding conventions and standards. It will create a longer discussion period, but that’s fine, IMHO.

If you’d like to continue with this RFC, I’d love to discuss it further with you and help you out. I believe it is a bit more than “just” syntax sugar, but I’d have to dig out my records implementation.

— Rob

I remember PHP from ~2000’s and PSR-4 and Composer were probably one of the biggest improvements to the ecosystem. However, I feel like a “2.0” version is long overdue. I have participated in some internals discussions that point out a fact from the other direction: PHP makes no imposition about file structure. 1-class-per-file is strictly a PSR-4 implementation of a custom autoloader which we have gotten used to for so long. I would really love to be able to declare small related classes/interfaces in a single file much like we can do with Typescript, but the current state of PHP “register your autoloader however you would like it” vs the current state of the community “PSR-4 is THE standard”, we end up between a rock and a hard place. I don’t particularly enjoy nested classes and how the syntax and its contexts get involved. Sure it would be nice to have private classes, but it gets quite cumbersome to have to do it while nesting classes within classes.

On the other hand, we can see from constructor property promotion that these little syntax sugar can be such a massive improvement to cognitive load, readability, writability, etc. I would really love to have something much like this RFC even if at first I need to do it as a one-line-per-file. To me, the more interesting chicken-egg problem to address is whether PHP needs to provide some change to symbols, namespaces, autoloader or if the community needs to expand PSR-4 in a way that allow us to not reject this RFC on the basis of “PSR-4 will drastically limit syntax sugar improvements”.

···

Marco Deleu

On Wed, Jul 16, 2025, at 10:44 AM, Deleu wrote:

On Wed, Jul 16, 2025 at 3:49 AM Rob Landers <rob@bottled.codes> wrote:

__

Why I haven't proposed it as a separate RFC: with PSR-4 being so popular, nobody is going to write one-line files to take advantage of this. Thus, when I was going to revisit nested classes later this year (after all the release shenanigans and some personal issues), I was planning to add this feature to the nested class v2 RFC (again). A lot of feedback I got on nested classes was "when would I use this?" -- and I suspect that would be a lot of the feedback you'd get here (see: PSR-4). I'm more convinced than ever that short constructors and nested classes create a chicken-and-egg problem. They only really make sense together; at least with our current coding conventions and standards. It will create a longer discussion period, but that's fine, IMHO.

If you'd like to continue with this RFC, I'd love to discuss it further with you and help you out. I believe it is a bit more than "just" syntax sugar, but I'd have to dig out my records implementation.

— Rob

I remember PHP from ~2000's and PSR-4 and Composer were probably one of
the biggest improvements to the ecosystem. However, I feel like a "2.0"
version is long overdue. I have participated in some internals
discussions that point out a fact from the other direction: PHP makes
no imposition about file structure. 1-class-per-file is strictly a
PSR-4 implementation of a custom autoloader which we have gotten used
to for so long. I would really love to be able to declare small related
classes/interfaces in a single file much like we can do with
Typescript, but the current state of PHP "register your autoloader
however you would like it" vs the current state of the community "PSR-4
is THE standard", we end up between a rock and a hard place. I don't
particularly enjoy nested classes and how the syntax and its contexts
get involved. Sure it would be nice to have private classes, but it
gets quite cumbersome to have to do it while nesting classes within
classes.

I will reiterate what I have said many times in the context of function autoloading:

The only autoloader that really matters in practice is Composer.

Composer supports "front-load this list of files". You can put whatever you want in there.

We have an opcache. I am really not concerned about the cost of front-loading a bunch of small functions or classes.

If you're using React, FrankenPHP, or many of the other new-wave run models, you have a persistent process anyway so just expect everything to get loaded.

So having a "dto.php" or "classes.php" file that Composer just front-loads on every request that contains a bunch of one-liner class definitions (or functions, or whatever) is perfectly fine, and works today.

The only thing that would need to change is for SA tools (mostly PHPStorm) to be less whiny if they see a class that doesn't match its file name. But I am quite confident JetBrains can figure out how to do that.

In short: This is not a real problem. There's no need for us to make it one.

--Larry Garfield

This works for me, but if I do it alone on my projects, it’s just an invitation for someone else to call it legacy garbate and undo it. Perhaps I’m alone in this bubble and everyone else is already doing it, but from where I’m standing that’s just a recipe for people to raise their eyebrows and feel confused. For better or worse, Composer “files” feature is nearly as flexible as PHP autoloader. I could make what I want work with either of them, but if every project has a different approach on how to do it, we’re slightly back to 2000’s PHP or we’re in 2020’s Node. Maybe I brought this upon myself by mentioning Typescript’s capabilities, but to be more precise, I do it (and love it) while working on Single File Components in VueJS, which is not a language-wide standard, but in its own corner it is a comprehensive and well established standard.

Should I have a single classes.php on my Composer files and put everything in there? Should it be one file per module? If someone on my team copy/paste a file like that into another module/project/repository/whatever and suddenly they’re seeing “PHP Error class not found” for 2 hours because this is such an uncommon error in modern PHP, is it his mistake for not understanding it or is it mine for creating something far away from obvious?

The blessing and the curse of PSR-4 is that it spoiled us (or maybe just me?) to:

  • never think about require/include
  • never think about composer.json
  • never think about how classes/interfaces/traits are located
  • IDEs will auto-import stuff so I don’t even need to think about use statement
  • I don’t know how to debug “Class not found” issues because the last time I saw an error like this was 5 years ago when I was trying to mess up with custom autoload capabilities in order to declare multiple symbols in a single file.

Maybe I’m alone in it and then it’s fine for it to be just my problem. I’m sharing here in case it’s also someone else’s problem and we can do something about it. But please don’t tell me it’s not a real problem.

···

Marco Deleu

On Wed, Jul 16, 2025, at 17:44, Deleu wrote:

On Wed, Jul 16, 2025 at 3:49 AM Rob Landers rob@bottled.codes wrote:

Why I haven’t proposed it as a separate RFC: with PSR-4 being so popular, nobody is going to write one-line files to take advantage of this. Thus, when I was going to revisit nested classes later this year (after all the release shenanigans and some personal issues), I was planning to add this feature to the nested class v2 RFC (again). A lot of feedback I got on nested classes was “when would I use this?” – and I suspect that would be a lot of the feedback you’d get here (see: PSR-4). I’m more convinced than ever that short constructors and nested classes create a chicken-and-egg problem. They only really make sense together; at least with our current coding conventions and standards. It will create a longer discussion period, but that’s fine, IMHO.

If you’d like to continue with this RFC, I’d love to discuss it further with you and help you out. I believe it is a bit more than “just” syntax sugar, but I’d have to dig out my records implementation.

— Rob

I remember PHP from ~2000’s and PSR-4 and Composer were probably one of the biggest improvements to the ecosystem. However, I feel like a “2.0” version is long overdue. I have participated in some internals discussions that point out a fact from the other direction: PHP makes no imposition about file structure. 1-class-per-file is strictly a PSR-4 implementation of a custom autoloader which we have gotten used to for so long. I would really love to be able to declare small related classes/interfaces in a single file much like we can do with Typescript, but the current state of PHP “register your autoloader however you would like it” vs the current state of the community “PSR-4 is THE standard”, we end up between a rock and a hard place. I don’t particularly enjoy nested classes and how the syntax and its contexts get involved. Sure it would be nice to have private classes, but it gets quite cumbersome to have to do it while nesting classes within classes.

I won’t comment on the composer stuff or autoloading for that matter. But to your point about nested classes – well, the entire point of nested classes was to make it easy for encapsulation:

class FooSelector {
public function byId($id): array { /* select by Id / }
class AsAdmin extends FooSelector {
public function byId($id): array { /
select by Id */ }
}
}

$selector = $isAdmin ? new FooSelector\AsAdmin : new FooSelector;

But where it really starts to get useful is when you can rewrite a return by array, into a simple object:

class FooSelector {
class Foo(int $id, string $bar);

public function byId($id): Foo { }
}

When working in established code, we very rarely write new classes when compared to greenfield systems, where you have to write every new class (data objects, services, controllers, repositories, etc). In greenfield php projects, you often reach for an array until you need to create a proper class. Instead of reaching for an array, or writing out an entire file + boilerplate class, you can just write a short, tightly scoped class… much like we used to do back before PSR-4. If you recall back then, we’d often put it in the same file because we always knew that FooSelector would always be included before you could get a Foo. (and yeah, it was a time bomb; it was only a matter of time before someone would create a Foo before they created a FooSelector and it would crash)

class Foo { /* */ }

class FooSelector { /* */ }

If you ever wanted to migrate it to a proper class, you’d just create a folder (FooSelector) and copy/paste the class into a new file and keep PSR-4 working just fine. In other words, trying to create a FooSelector\Foo when Foo was nested, would properly autoload the correct file.

Nested classes v2 won’t include visibility. I think that just complicated things too much.

But yes, in established code bases, they probably don’t make as much sense, but that was the main problem I was trying to solve: the annoyance of choosing between an array – or the boilerplate of creating a new class just to hold a few fields.

On the other hand, we can see from constructor property promotion that these little syntax sugar can be such a massive improvement to cognitive load, readability, writability, etc. I would really love to have something much like this RFC even if at first I need to do it as a one-line-per-file. To me, the more interesting chicken-egg problem to address is whether PHP needs to provide some change to symbols, namespaces, autoloader or if the community needs to expand PSR-4 in a way that allow us to not reject this RFC on the basis of “PSR-4 will drastically limit syntax sugar improvements”.

Marco Deleu

I’d also love to see this get implemented and I’ve offered to help as much as I can.

— Rob

Hi all,

On Jul 16, 2025, at 11:40, Deleu <deleugyn@gmail.com> wrote:

...

The blessing and the curse of PSR-4 is that it spoiled us (or maybe just me?) to:

- never think about `require/include`
- never think about composer.json
- never think about how classes/interfaces/traits are located
- IDEs will auto-import stuff so I don't even need to think about `use` statement
- I don't know how to debug "Class not found" issues because the last time I saw an error like this was 5 years ago when I was trying to mess up with custom autoload capabilities in order to declare multiple symbols in a single file.

As the lead on PSR-4, I appreciate (and am sympathetic to) this list, as well as the pros & cons of one-class-per-file (which originated with PSR-0 and the Horde/PEAR standards before it).

Maybe I'm alone in it and then it's fine for it to be just my problem. I'm sharing here in case it's also someone else's problem and we can do something about it. But please don't tell me it's not a real problem.

You're not alone; I hear similar stories from time to time. Larry may be many things, but he's definitely not the final authority on what is and is not a "real problem."

I am open to developing an extension of, or alternative to, PSR-4 autoloading that would allow for multiple-classes-per-file; please contact me off-list if you're interested in pursuing that idea.

-- pmj

Good catch for multi-classes per file with such feature, but I think it’s not the time to do it.

As an alternative way to find the class is to look at the all files in the namespace:

src/App/Controller/
---- IndexController.php
---- BlogController.php

IndexController.php contains

namespace App\Controller;

class IndexController {}

class IndexGetRequest {}
class ItemGetRequest {}
class ItemPostRequest {}

So lookup for \App\Controller\ItemGetRequest will look at src/App/Controller/*.php files, caching the rest of the classes found during the lookup.
Or something like that.

I think we should discuss the idea of the Short Constructor here. At least it does not require autoloading changes, but thanks for mentioning it.
Btw, all possible changes of the autoloading may be proposed to Composer project without any RFC right now.

···

Best regards,

Dmitrii Derepko.
@xepozz

Hi Dmitry,

On Jul 24, 2025, at 12:41, Dmitry Derepko <xepozzd@gmail.com> wrote:

Good catch for multi-classes per file with such feature, but I think it's not the time to do it.

...

I think we should discuss the idea of the Short Constructor here. At least it does not require autoloading changes

Not as part of PHP internals anyway -- agreed.

Btw, all possible changes of the autoloading may be proposed to Composer project without any RFC right now.

While we are here, I am working up a more-than-one class per file autoloader at GitHub - motophp/autoload: More-than-one class-per-file autoloader for PHP. -- if it works out, I expect I'd submit it for the Composer folks for their consideration.

-- pmj