Let's start getting specific so we can make some progress.
The goals of this RFC are fairly straightforward:
* Introduce the `static` keyword at the class level to preclude the
need to create a private constructor. That is, `__construct` would
be invalid in a static class.
* Prohibit instantiation of a static class with a language-level error.
* Prohibit declaration of instance members in a static class with a
language-level error.
However, as ever, there's a devil in the details. In particular, we need
to consider the following:
1. Since a "static class" implies all members are static, should we
still allow explicit static method declarations with the `static` keyword?
2. Should `static` imply `final`?
2a. If yes, should `final` still be allowed to be explicitly
declared, despite being implied?
3. Should a "static class" prohibit inheritance?
4. Should a "static class" permit state?
5. Should traits be permitted in a static class?
6. Which magic methods (if any) should be valid in a static class?
Based on my current understanding, I would propose the following answers
to these questions:
1. In order to make upgrading simple and keep method intentions
clear, `static` should not only be valid but also required on each
method declaration, as usual for static methods.
2. Inheritance doesn't make much sense in a purely static context,
despite the fact that PHP has a static resolution operator; I often find
this is an anti-pattern. In any case, this is a non-BC issue if we lock
down inheritance for now and later decide to open it up. Disabling
inheritance also is in-line with the C# implementation of the same.
2a. Since under this proposal, `final` is implied, it should not be
necessary (or allowed) to be specified. Upgrading would be simply a case
of replacing `final` with `static` in-place.
3. As already mentioned, inheritance in a purely static context
doesn't make much sense, and it's a non-BC break to prohibit it and
later enable it. This decision is also in-line with the C# implementation.
4. Perhaps the most contentious decision, we could disable state and
later enable it if there is a need, without BC. I personally cannot
think of a time when I needed state in a static class. That said, I do
not agree with disabling state within the language. In case someone is
relying on static state in such a class, upgrading would be impossible;
they would instead have to avoid marking the class as static, which
defeats the purpose of this RFC. I believe we should support state, and
if someone dislikes static state, they should enforce that with a code
style rule in their project; this is not something that should be
prohibited by the language itself as "regular" classes already allow this.
5. Provided a trait follows the rules of the static class (i.e. all
members are static), it seems to me this should be allowed, though I
have little use for it myself.
6. Given there are many magic methods, this topic probably deserves a
separate discussion; it is not something I have spent a lot of time on
thus far so it is just included for visibility at this time.
If there are any strongly dissenting opinions on any of these points, or
any significant points I may have missed, please share. Otherwise, I
would be happy to draw up and RFC along these lines (notwithstanding I
have no RFC karma at present), followed by an implementation once all
outstanding questions are answered.
Cheers,
Bilge
On 15/06/2024 14:53, Rowan Tommins [IMSoP] wrote:
On 15/06/2024 12:16, Bilge wrote:
I want to introduce the `static` keyword at the class declaration
level. That is, the following would be valid: `static class Foo {}`.
This has been proposed before, and was rejected at vote. It was nearly
10 years ago, so opinions may have changed, but it would be worth
reading through the prior discussion to anticipate or counter the
objections raised, and avoid re-treading the same ground.
- RFC: https://wiki.php.net/rfc/abstract_final_class
- Pre-vote discussion threads: https://externals.io/message/79211 and
https://externals.io/message/79338
- Final vote thread: https://externals.io/message/79601
Searching my list archive, I find that it came up again a few months
ago, which I'd entirely forgotten: https://externals.io/message/121717
Slightly tangential, but some of the same discussion also came up on
these rather lengthy threads about "static class constructors":
https://externals.io/message/84602 and https://externals.io/message/85779
Regards,