> On Jun 16, 2024, at 5:17 AM, Bilge <[email protected]> wrote:
>
> 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:
>
To start, any limitations imposed on these new static classes that current classes can do that are
not intrinsically linked to their "staticness" would result in developers grudgingly
writing a class "statically" that is not declared as static. Imposing restrictions on
features that developers use in the wild would certainly cause them to consider the feature to be
dubiously excluded.
Not supporting all features used in the wild would result in developers not being able to use static
classes for new and/or refactored code if they believe they need those excluded features. This would
stop developers from signaling their intent to readers of their code and would stop developers from
being able to rely on reflection to discern static classes for new and/or refactored code when that
otherwise could have been possible.
Disabling existing features just for static classes would result in creating two forms of static
classes — explicit and implicit — and that IMO would be a miss for the addition of static
classes.
That said...
> 1. Since a "static class" implies all members are static, should we still allow
> explicit static method declarations with the static
keyword?
>
Yes, but optional.
Supporting the static keyword
for members would ease the transition for tooling, and
support those who prefer to be explicit in all the things.
OTOH, of all the things I mention below, this is my least firmly-held opinion.
> 2. Should static
imply final
?
>
No.
The primary PHP framework I wrote before I quite working professionally in PHP — although others
still use it — has a series of implied static classes, all of which inherit from a base implied
static class that provided services to all other implied static classes. To update this library to
a newer version of PHP with static classes would not be possible if static classes are assumed to be
final
.
Further, Laravel — which I have never used but is simultaneously the most beloved framework in PHP
but also the most hated, depending on who you ask — has a base Model
class that
Eloquent models inherit from, and a BaseController
for custom controllers. Enforcing
final
would leave Laravel out in the lurch for classes that are exactly the type of
classes that should be declared static.
If a developer wants their declared static class to be final they should be required to use the
final
keyword, IMO.
BTW, see #4 and #5 why this is important.
> 3. Should a "static class" prohibit inheritance?
>
Isn't #3 just a rewording of #2?
> 4. Should a "static class" permit state?
>
Absolutely, without a doubt.
My PHP library uses static properties to keep track of certain data which I treated as immutable —
registering business information for use by static factory methods, and in some cases the factory
methods use arrays to store instances they create for processing and/or dispensing on demand late by
other static methods.
Laravel uses static properties in their service containers such as
Illuminate\Support\Facades\App
, their Cache facade uses static properties, Eloquent
models maintain state in static properties, and developer written factory classes often use static
properties to track instances.
While we can ignore my library it would be much harder to ignore Laravel's use of state in
static properties.
> 5. Should traits be permitted in a static class?
>
Of course.
Laravel makes extensive use of traits in their implied static classes, in their core framework and
in Eloquent models, and they encourage Laravel application developers to use traits in their
applications.
Traits are a valuable code structuring mechanism as an alternate to inheritance more like
containment, and not supporting traits would, again, be leaving developers depending on it out in
the cold.
Also, final/inheritance might not be as critical to support if it were not for one capability that
PHP's traits are glaringly missing and that is their inability to allow developers to declare
properties and methods as private to the trait itself.
Of course if we add trait-private to traits then it would be less problematic to implied
final
/not support inheritance, but I doubt we'd want to couple this potential RFC
with one that hasn't even been considered yet.
Even so, not supporting inheritance would mean not allowing implied static classes that use
inheritance to be refactored to use the static declaration.
> 6. Which magic methods (if any) should be valid in a static class?
>
Unless I am mistaken, the only magic method that support static function calls is
__callStatic()
as everything else deals with instances, so I assume that it is the only
one that needs to be supported.
And yes, IMO it is critical to support __callStatic()
since Laravel Facades (as well as
my own library) make use of it, and in Laravel's case, extensive use.
Of course there may(?) be newer PHP features on the horizon that are an alternate to
__callStatic()
but supporting __callStatic()
would make it easier for
developers to move to static classes as even automated tooling could make the conversion if
__callStatic()
and all other features used in the wild are supported.
Anyway, that is my take. #fwiw
-Mike
P.S. To learn about Laravel's uses of implied static classes I asked ChatGPT[1], so if I got
anything wrong about Laravel I apologize as I was relying on ChatGPT not to hallucinate on this
topic. I assumed it was unlikely to hallucinate given there was so much info on the web there is
regarding Laravel for ChatGPT to train on.
[1] https://chatgpt.com/share/79eb330b-69ae-4104-b2ac-6e77955ec914