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:
- 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,
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:
- 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/19133Many 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
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:
- 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
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
__
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
On Wed, Jul 16, 2025 at 12:59 PM Larry Garfield larry@garfieldtech.com
wrote:
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
Hi all,
...
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,
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 https://github.com/motophp/autoload -- if it works out, I expect I'd submit it for the Composer folks for their consideration.
-- pmj
__
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