Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.
This work is based on the previous discussion thread on this list of the
same name, and hopefully captured all the relevant details,
notwithstanding anything unanticipated that may present itself during
the implementation. Let me know if you feel anything important has been
missed. I am aware it omits to mention specifics about messages so
emitted when runtime or compile-time errors occur, but I anticipate this
can be hashed out in the PR, unless consensus indicates otherwise.
I am aware this idea is not supported by everyone, but there seemed to
be enough positive voices for it to be worth a shot. I'd like to get a
better idea of where people might stand when it comes down to a vote,
now there is a formal RFC, so we know whether it's worth completing the
implementation, although any sentiments so proffered are of course not a
commitment to vote any particular way and nobody should feel compelled
to speak to that unless comfortable. Looking forward to feedback!
Cheers,
Bilge
Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.This work is based on the previous discussion thread on this list of the
same name, and hopefully captured all the relevant details,
notwithstanding anything unanticipated that may present itself during
the implementation. Let me know if you feel anything important has been
missed. I am aware it omits to mention specifics about messages so
emitted when runtime or compile-time errors occur, but I anticipate this
can be hashed out in the PR, unless consensus indicates otherwise.I am aware this idea is not supported by everyone, but there seemed to
be enough positive voices for it to be worth a shot. I'd like to get a
better idea of where people might stand when it comes down to a vote,
now there is a formal RFC, so we know whether it's worth completing the
implementation, although any sentiments so proffered are of course not a
commitment to vote any particular way and nobody should feel compelled
to speak to that unless comfortable. Looking forward to feedback!Cheers,
Bilge
On the point of getting feedback on where people will vote now there's an RFC, I can only say with all honesty "Good luck." :-) This is by far the biggest challenge of making an RFC: the lack of a meaningful sense of how something will be received before the actual vote. Welcome to the club.
For the record, as previously stated, I will be voting No on this RFC.
--Larry Garfield
On the point of getting feedback on where people will vote now there's an RFC, I can only say with all honesty "Good luck." :-) This is by far the biggest challenge of making an RFC: the lack of a meaningful sense of how something will be received before the actual vote. Welcome to the club.
For the record, as previously stated, I will be voting No on this RFC.
--Larry Garfield
Thanks, Larry. I appreciate that, and on that point, I appreciate you
being clear where you stand.
Cheers,
Bilge.
<snip> > > For the record, as previously stated, I will be voting No on this RFC.Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.This work is based on the previous discussion thread on this list of the
same name, and hopefully captured all the relevant details,
notwithstanding anything unanticipated that may present itself during
the implementation. Let me know if you feel anything important has been
missed. I am aware it omits to mention specifics about messages so
emitted when runtime or compile-time errors occur, but I anticipate this
can be hashed out in the PR, unless consensus indicates otherwise.I am aware this idea is not supported by everyone, but there seemed to
be enough positive voices for it to be worth a shot. I'd like to get a
better idea of where people might stand when it comes down to a vote,
now there is a formal RFC, so we know whether it's worth completing the
implementation, although any sentiments so proffered are of course not a
commitment to vote any particular way and nobody should feel compelled
to speak to that unless comfortable. Looking forward to feedback!
Having read this thread, and the previous one from half a year ago, I
will do so too. In short, we shouldn't be encouraging static classes as
a bag of static functions, that ought to be just namespaced functions.
cheers,
Derick
Having read this thread, and the previous one from half a year ago, I
will do so too. In short, we shouldn't be encouraging static classes as
a bag of static functions, that ought to be just namespaced functions.
Which brings us back to the age-old problem that functions can’t be autoloaded. Me, I want first-class modules, but until we have those, I have to settle for classes in the meantime. Scala/Kotlin-like “companion objects” might be a good all-round substitute though.
Cheers,
chuck
Having read this thread, and the previous one from half a year ago,
I will do so too. In short, we shouldn't be encouraging static
classes as a bag of static functions, that ought to be just
namespaced functions.Which brings us back to the age-old problem that functions can’t be
autoloaded. Me, I want first-class modules, but until we have those, I
have to settle for classes in the meantime. Scala/Kotlin-like
“companion objects” might be a good all-round substitute though.
There has been some work done on function autoloading too:
https://wiki.php.net/rfc/core-autoloading
cheers,
Derick
Having read this thread, and the previous one from half a year ago,
I will do so too. In short, we shouldn't be encouraging static
classes as a bag of static functions, that ought to be just
namespaced functions.Which brings us back to the age-old problem that functions can’t be
autoloaded. Me, I want first-class modules, but until we have those, I
have to settle for classes in the meantime. Scala/Kotlin-like
“companion objects” might be a good all-round substitute though.There has been some work done on function autoloading too:
https://wiki.php.net/rfc/core-autoloadingcheers,
DerickMy bad, I thought "top post" meant the same thing in mailing lists as it
does in forums. I am now aware of my mistake and it won't happen again. Can
we address my actual points now?
Lanre
There has been some work done on function autoloading too:
https://wiki.php.net/rfc/core-autoloading
Fantastic! I still want modules and/or companion objects of course... I wonder whether the autoloading machinery could be bent to such a purpose, or am I smoking the bad stuff again?
—c
In JavaScript/Typescript, we can declare functions that are local to the
current file by not exporting them. In C/C++ this is achieved by simply
writing the function in the implementation file as opposed to the header.
However, achieving a similar level of privacy in PHP requires using private
static methods, or else you incur the overhead of creating an object for
stateless functions. How do you propose handling such cases using
namespaced functions? Can you think of any scenarios where hiding non-API
functions might be necessary? I'm curious why you keep returning to
namespaced functions when they don't fulfill the same role.
Cheers,
Lanre
<snip> > > For the record, as previously stated, I will be voting No on this RFC.Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.This work is based on the previous discussion thread on this list of
the
same name, and hopefully captured all the relevant details,
notwithstanding anything unanticipated that may present itself during
the implementation. Let me know if you feel anything important has
been
missed. I am aware it omits to mention specifics about messages so
emitted when runtime or compile-time errors occur, but I anticipate
this
can be hashed out in the PR, unless consensus indicates otherwise.I am aware this idea is not supported by everyone, but there seemed to
be enough positive voices for it to be worth a shot. I'd like to get a
better idea of where people might stand when it comes down to a vote,
now there is a formal RFC, so we know whether it's worth completing
the
implementation, although any sentiments so proffered are of course not
a
commitment to vote any particular way and nobody should feel compelled
to speak to that unless comfortable. Looking forward to feedback!Having read this thread, and the previous one from half a year ago, I
will do so too. In short, we shouldn't be encouraging static classes as
a bag of static functions, that ought to be just namespaced functions.cheers,
Derick
In JavaScript/Typescript, we can declare functions that are local to
the current file by not exporting them. In C/C++ this is achieved by
simply writing the function in the implementation file as opposed to
the header. However, achieving a similar level of privacy in PHP
requires using private static methods, or else you incur the overhead
of creating an object for stateless functions. How do you propose
handling such cases using namespaced functions? Can you think of any
scenarios where hiding non-API functions might be necessary? I'm
curious why you keep returning to namespaced functions when they don't
fulfill the same role.Cheers,
Lanre
Please don't top-post.
PHP has no concept of packages at present, and thus no concept of package-level scope. A private static method is private not to a file or package, but to that class. (The class and file usually correlate in practice, but there's nothing in the language that mandates that.) I would love to have a concept of packages that we could use for scope, as most more recent languages have concluded that is the correct level at which to enforce visibility, NOT objects/classes. That's an entirely separate question, however.
For marking a function as "package private", the same way you would for a package-private class today: @internal docblock. It's not ideal (the ideal would require packages), but it still communicates the intent, has worked for classes for 15 years at least, and signals "if you use this class/function/thing and it breaks later, that's on you, don't come crying to me."
(ab)using static classes to emulate a pseudo-single-class-package is... abusing static.
To be blunt, 90% of uses of static methods in PHP are a sign the developer doesn't actually understand OOP and is just writing procedural code with more steps. The other 10% are either named constructors or cases that can now be replaced with attributes.
--Larry Garfield
That isn't a top post, look again.And I am not referring to
packages,rather to the ability to define functions that aren't exposed to
the users of a library. C doesn't have packages either yet this is possible
in it. And marking it as internal is not the same thing at all. I am not
going to argue about why a developer would use static methods and whether
that is actually a sign that the developer doesn't understand OOP. But I do
want to get this straight. Instead of actually hiding the function, your
idea is to mark it with @internal (via PHPDoc)? To you, that solves the
problem?
On Wed, Jun 26, 2024 at 1:46 PM Larry Garfield larry@garfieldtech.com
wrote:
In JavaScript/Typescript, we can declare functions that are local to
the current file by not exporting them. In C/C++ this is achieved by
simply writing the function in the implementation file as opposed to
the header. However, achieving a similar level of privacy in PHP
requires using private static methods, or else you incur the overhead
of creating an object for stateless functions. How do you propose
handling such cases using namespaced functions? Can you think of any
scenarios where hiding non-API functions might be necessary? I'm
curious why you keep returning to namespaced functions when they don't
fulfill the same role.Cheers,
LanrePlease don't top-post.
PHP has no concept of packages at present, and thus no concept of
package-level scope. A private static method is private not to a file or
package, but to that class. (The class and file usually correlate in
practice, but there's nothing in the language that mandates that.) I would
love to have a concept of packages that we could use for scope, as most
more recent languages have concluded that is the correct level at which to
enforce visibility, NOT objects/classes. That's an entirely separate
question, however.For marking a function as "package private", the same way you would for a
package-private class today: @internal docblock. It's not ideal (the ideal
would require packages), but it still communicates the intent, has worked
for classes for 15 years at least, and signals "if you use this
class/function/thing and it breaks later, that's on you, don't come crying
to me."(ab)using static classes to emulate a pseudo-single-class-package is...
abusing static.To be blunt, 90% of uses of static methods in PHP are a sign the developer
doesn't actually understand OOP and is just writing procedural code with
more steps. The other 10% are either named constructors or cases that can
now be replaced with attributes.--Larry Garfield
That isn't a top post, look again.
It was.
If people point out you're doing something against this list's
guidelines, don't reply with "it wasn't" in a snarky way.
cheers,
Derick
Also I specifically said "we can declare functions that are local to the
current file by not exporting them.", Where did you get "package private"
from?
On Wed, Jun 26, 2024 at 1:46 PM Larry Garfield larry@garfieldtech.com
wrote:
In JavaScript/Typescript, we can declare functions that are local to
the current file by not exporting them. In C/C++ this is achieved by
simply writing the function in the implementation file as opposed to
the header. However, achieving a similar level of privacy in PHP
requires using private static methods, or else you incur the overhead
of creating an object for stateless functions. How do you propose
handling such cases using namespaced functions? Can you think of any
scenarios where hiding non-API functions might be necessary? I'm
curious why you keep returning to namespaced functions when they don't
fulfill the same role.Cheers,
LanrePlease don't top-post.
PHP has no concept of packages at present, and thus no concept of
package-level scope. A private static method is private not to a file or
package, but to that class. (The class and file usually correlate in
practice, but there's nothing in the language that mandates that.) I would
love to have a concept of packages that we could use for scope, as most
more recent languages have concluded that is the correct level at which to
enforce visibility, NOT objects/classes. That's an entirely separate
question, however.For marking a function as "package private", the same way you would for a
package-private class today: @internal docblock. It's not ideal (the ideal
would require packages), but it still communicates the intent, has worked
for classes for 15 years at least, and signals "if you use this
class/function/thing and it breaks later, that's on you, don't come crying
to me."(ab)using static classes to emulate a pseudo-single-class-package is...
abusing static.To be blunt, 90% of uses of static methods in PHP are a sign the developer
doesn't actually understand OOP and is just writing procedural code with
more steps. The other 10% are either named constructors or cases that can
now be replaced with attributes.--Larry Garfield
Hi Larry,
PHP has no concept of packages at present, and thus no concept of package-level scope.
Not entirely true.
PHP has static classes, which are stand-ins for packages for as long as PHP does not inherently support the concept of packages.
Arguing "that is abusing static" without offering an alternative is just Puritanistic logic that ignores pragmatic real world needs.
For marking a function as "package private", the same way you would for a package-private class today: @internal docblock. It's not ideal (the ideal would require packages), but it still communicates the intent, has worked for classes for 15 years at least, and signals "if you use this class/function/thing and it breaks later, that's on you, don't come crying to me."
Not only is @internal docblock
not ideal, it sets up those internal properties to be infected with usage as explained by Hyrum's Law[1]. Thus providing @internal docblock
as if it were a viable alternative to package private is essentially a non-serious argument.
PHP has no concept of packages at present, and thus no concept of package-level scope. A private static method is private not to a file or package, but to that class. (The class and file usually correlate in practice, but there's nothing in the language that mandates that.) I would love to have a concept of packages that we could use for scope, as most more recent languages have concluded that is the correct level at which to enforce visibility, NOT objects/classes. That's an entirely separate question, however.
If you really want people to stop "abusing static" then drive to address that entirely separate question. Otherwise let others who are more pragmatic give the language features that they need.
As a quick aside, I would argue that PHP should look at its biggest warts — which to me include but are not limited to autoloading and namespaces — and deprecate them to be replaced with a proper package system that leverages a symbol compiler instead of autoloading and that ejects the god-awful choice of using the escape character for package name separation.
But I digress.
To be blunt, 90% of uses of static methods in PHP are a sign the developer doesn't actually understand OOP and is just writing procedural code with more steps. The other 10% are either named constructors or cases that can now be replaced with attributes.
Speaking of best practices, there is a growing contingent of software developers who feel that OOP should not be the future of software[2], e.g. that it was "a good idea at the time" but now no longer.
My point here is that PHP should not let entrenched dogma drive language design but instead pragmatically evolve as other languages are also evolving.
-Mike
[1] https://www.laws-of-software.com/laws/hyrum/ https://www.laws-of-software.com/laws/hyrum/
[2] https://news.ycombinator.com/item?id=8676872 <https://news.ycombinator.com/item?id=8676872
we shouldn't be encouraging static classes as
a bag of static functions, that ought to be just namespaced functions.
I understand this is the prevailing preference of a certain few,
including (but not limited to) yourself and Larry. Nevertheless, classes
as a bag of static functions is a phenomenon that exists and will
continue to exist in PHP until such a time as static
is completely
removed from the language, so I don't really understand the avoidance of
adding, in the interim, what seems like just a missing part of an
existing feature.
However, I still want to understand why a file of functions is strictly
better than a class of functions. What are the benefits of a file over a
class?
For me, I dislike importing individual functions. It is often the case
that, when such logic is so grouped in a static class, where we use one
we may use several such functions. In such a case, we only need a single
import statement instead of one for each function. This seems like a
clear benefit. Even in the case that I only use one, I still prefer to
import a class over a function, because it has better support in my
editor and doesn't stick out like a sore thumb in the list of imports
(why should it?).
Cheers, Bilge
we shouldn't be encouraging static classes as a bag of static functions, that ought to be just namespaced functions.
cheers,
Derick
Can someone clue me in as to why grouping related functions in a file
with nothing but a namespace is strictly better than those same related
functions grouped as members of a class? It doesn't have to be Larry or
Derick, because even though they have expressed this view, I am aware
they are not the only ones whom hold it. Anyone who can shed some light
on this perspective is welcome to comment.
Cheers,
Bilge
we shouldn't be encouraging static classes as a bag of static functions, that ought to be just namespaced functions.
cheers,
DerickCan someone clue me in as to why grouping related functions in a file with
nothing but a namespace is strictly better than those same related
functions grouped as members of a class? It doesn't have to be Larry or
Derick, because even though they have expressed this view, I am aware they
are not the only ones whom hold it. Anyone who can shed some light on this
perspective is welcome to comment.Cheers,
Bilge
It isn't implicitly better, but if PHP had proper support for autoloading
functions, I would at least consider them equivalent when all the
functions/methods are public.
My primary language is C++, where the distinction is even blurrier since
both static class members and namespace members are accessed with '::'. For
example, X::Y() could be a namespaced function or a static method, and it
doesn't actually matter which it is under the hood since they are
functionally identical.
In PHP, however, putting all your functions in a namespace is less
performant than using static classes. For instance, if you have ten
functions.php files each for a separate namespace, Composer will load all
ten for every single request, regardless of whether they are used.
Additionally, if you install a Composer package that registers some
functions, those will also be loaded for every request.
Cheers,
Lanre
we shouldn't be encouraging static classes as
a bag of static functions, that ought to be just namespaced functions.cheers,
DerickCan someone clue me in as to why grouping related functions in a file with nothing but a namespace is strictly better than those same related functions grouped as members of a class? It doesn't have to be Larry or Derick, because even though they have expressed this view, I am aware they are not the only ones whom hold it. Anyone who can shed some light on this perspective is welcome to comment.
I cannot answer your question as posed but I can give you a counter-reason, one supporting the use of static classes as a bag of static functions, at least with the feature set of PHP 8.4 and prior.
If a developer needs to hide global state — and there are valid reasons for maintaining global state using static classes along with a related set of static functions. Minimally, when using streams with include*()/require*() e.g. include("myprotocol://${handle}") namespaces simply do not have the necessary visibility scoping features and thus are not an option.
I am currently working on a PoC for packages in userland that uses static classes exactly in this way. I will hopefully be able to share working code for that soon.
-Mike
P.S. None of include*()/require*() accept a stream context AFAICT. If they did a developer could pass in a dependency object as a context, but currently (again, AFAICT) there is no way to associate a dependency object with an include*()/require*() call. The only approach I have been able to identify to allow access to retrieve and update a dependency object is to use a key into a array in a private static property with public static get/set methods.
If context were added to include*()/require*() and/or visibility scoping where added to symbols within namespaces then this use-case would no longer be an argument for static classes. But unless and until then, static classes are the only way to go. #fwiw
Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.
Hi! and good luck with the RFC.
While I don't use static classes, I can see how this can be used by others.
I worked in big projects that used too many libraries, and when those
libraries have functions.php file, they pile up and loading the composer
autoloader can take a small dent on performance of each request.
Having functions grouped by a class that can autoloader instead of a file
is an advantage that should be spelled out as an use case.
Feedback:
-
I agree that static classes may extend other non-static classes (that
might have some static behavior).
But I think that static classes should be extended only by other static
classes, or at least for the first iteration of these feature.
This should be documented more in the RFC, no matter how it ends up being.
1.1 I think using a static class as a type should be considered an error,
as there will never be instances of it if we consider all child classes
will also be static classes.
Of course, this cannot be an error on php side given the class per file
loading separation. -
__set_state() is strongly linked to exporting a class instance as a
valid php string, and is used to reconstruct the class instance upon
execution.
Considering we forbid instances, we should not support __set_state(). If
you think otherwise, please share an example how it can be used.
Regards,
Alex
Hi Internals! I am pleased to present my first RFC: Static class <https://wiki.php.net/rfc/static_class>.
Hi! and good luck with the RFC.
Hi Alex, and thanks for your excellent feedback!
While I don't use static classes, I can see how this can be used by
others.
It is my sincere hope that everyone will vote with similar empathy.
Feedback:
- I agree that static classes may extend other non-static classes
(that might have some static behavior).
To be clear, they must /exclusively/ have static members, not just /some/.
But I think that static classes should be extended only by other
static classes, or at least for the first iteration of these feature.
This should be documented more in the RFC, no matter how it ends up being.
This is an interesting debate, and something we may end up doing. I am
currently undecided if it would be better to enforce full static class
hierarchy, but I could definitely be so convinced.
1.1 I think using a static class as a type should be considered an
error, as there will never be instances of it if we consider all child
classes will also be static classes.
Of course, this cannot be an error on php side given the class per
file loading separation.
This is a very interesting point that I had not considered. I agree, it
should be correct to forbid type hinting static classes. However, if I
understood you correctly, we cannot actually implement that? My
knowledge of engine internals is too weak to know the correct answer
here. If it is possible, I think we should do it.- __set_state() is strongly linked to exporting a class instance as a
valid php string, and is used to reconstruct the class instance upon
execution.
Considering we forbid instances, we should not support __set_state().
If you think otherwise, please share an example how it can be used.
Thank you for catching this. This is strictly a mistake on my part. I
have never used, or even heard of, __set_state() in my life. I was
merely perusing the magic methods to make sure I caught them all and it
seemed, at a glance, this might apply to static classes, but as you
point out, if this indeed requires an instance then it does not apply. I
will remove this from the next version of the RFC, which I shall publish
imminently.
Many thanks,
Bilge
This work is based on the previous discussion thread on this list of the
same name, and hopefully captured all the relevant details,
notwithstanding anything unanticipated that may present itself during
the implementation. Let me know if you feel anything important has been
missed. I am aware it omits to mention specifics about messages so
emitted when runtime or compile-time errors occur, but I anticipate this
can be hashed out in the PR, unless consensus indicates otherwise.
Hi Bilge,
I was reading the mailing list discussions, and I am glad you created the RFC.
Personally, I think this will be a useful feature. Just like we have
readonly
properties and readonly
classes, I don't see why we can't
have static methods. I also saw in the draft PR that it does not
require a lot of changes to the engine to have this.
I'd like to propose to add some more information and points addressed
in the RFC. This is of course merely a suggestion, but it's something
I was thinking when reading the RFC.
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ? - Can a subclass extend a static parent class without using the
static
keyword in the subclass? This will avoid a lot of BC issues
if a library decides to declare classes as static. - Are there any opt-out mechanisms for subclasses?
- Can you mark interfaces, abstract classes, and Enums as static?
Hi
Personally, I think this will be a useful feature. Just like we have
readonly
properties andreadonly
classes, I don't see why we can't
have static methods. I also saw in the draft PR that it does not
require a lot of changes to the engine to have this.I'd like to propose to add some more information and points addressed
in the RFC. This is of course merely a suggestion, but it's something
I was thinking when reading the RFC.
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?
To quote myself from the #[\Override] RFC:
This RFC proposes an attribute instead of a keyword, because contrary to other modifiers (e.g. visibility) that are part of the method signature, the attribute does not affect behavior or compatibility for users that further extend a given class and neither does it affect users that call the method. It is purely an assistance to the author of a given class.
Marking a class as 'static' does affect how the class may be used and
thus the static-ness is part of the public API. Therefore it should be a
keyword. Everything else would also be inconsistent with final classes
effectively making all members final and readonly classes making all
members readonly.
- Can a subclass extend a static parent class without using the
static
keyword in the subclass? This will avoid a lot of BC issues
if a library decides to declare classes as static.
It should not. See: readonly classes. I also believe that static classes
should be implictly final. Given that no objects of such a class can
exist, they cannot be exchanged by a different class anyways and
inheritance is not meant for code reuse.
Best regards
Tim Düsterhus
It should not. See: readonly classes. I also believe that static classes
should be implictly final. Given that no objects of such a class can
exist, they cannot be exchanged by a different class anyways and
inheritance is not meant for code reuse.
I don't agree that they should be implicitly final, or that inheritance is
not meant for code reuse. It is currently possible eg:
https://gist.github.com/oplanre/6894f56fb61134ee5ea93cf262ba3662 and I
don't see why that should change, unless you have any solid reasons as to
why.
Lanre
Marking a class as 'static' does affect how the class may be used and thus the static-ness is part of the public API. Therefore it should be a keyword. Everything else would also be inconsistent with final classes effectively making all members final and readonly classes making all members readonly.
Very insightful; that is a great rule of thumb.
I also believe that static classes should be implictly final. Given that no objects of such a class can exist, they cannot be exchanged by a different class anyways
I object here.
There are functions in classes that I have built in the past that are static and also benefit from inheritance. Could they be called directly on the base class; yes? But that is less elegant and increases complexity with two levels of inheritance are needed.
Specifically the functionality I am thinking of is the base class is generic functionality for factory functions and then child factory functions implement use-case specific logic for the type of the object produced. For example, each of these functions has a MakeNew(...) function, and children call self::MakeNew(...).
Base
-- Term
-- User
-- BasePost
-- Post
-- Page
That is a subset of classes I used, and those classes were designed for use with WordPress.
Further, these classes implemented "hooks" in WordPress. Using inheritance allowed all the hooks to be managed without repeating them in many places, being able to modify them for a class-specific need, and also without accidentally forgetting to add them.
and inheritance is not meant for code reuse.
Just because code reuse in inheritance can be problematic it does not have to be in all-cases. Moderation in all things. I used that approach for 10+ years and never once had any of the problems people claim about using inheritance for code reuse. This was likely because my needs were constrained by the use-case and by nature did not grow out of control with complexity.
So I would really hate to finally get static classes but still not be able to use them as intended for select use-cases only because someone decided without knowing all applicable use-cases that they did not like the idea of people using inheritance.
-Mike
and inheritance is not meant for code reuse.
Just because code reuse in inheritance can be problematic it does not have
to be in all-cases. Moderation in all things. I used that approach for 10+
years and never once had any of the problems people claim about using
inheritance for code reuse. This was likely because my needs were
constrained by the use-case and by nature did not grow out of control with
complexity.
My experience is the opposite. There are subtle bugs I keep running into
with static function and properties causing unexpected behavior. I'm not
against having static classes open by default for the sake of consistency,
though my preference would be to avoid the headache altogether and just
make them final by default so I won't ever have to deal with it. Would
traits not solve the problem of horizontal reuse?
and inheritance is not meant for code reuse.
Just because code reuse in inheritance can be problematic it does not
have to be in all-cases. Moderation in all things. I used that approach for
10+ years and never once had any of the problems people claim about using
inheritance for code reuse. This was likely because my needs were
constrained by the use-case and by nature did not grow out of control with
complexity.My experience is the opposite. There are subtle bugs I keep running into
with static function and properties causing unexpected behavior. I'm not
against having static classes open by default for the sake of consistency,
though my preference would be to avoid the headache altogether and just
make them final by default so I won't ever have to deal with it. Would
traits not solve the problem of horizontal reuse?
Sounds like a 'you' problem. Can you go into more details about said subtle
bugs? With examples if possible?
Lanre
and inheritance is not meant for code reuse.
Just because code reuse in inheritance can be problematic it does not have to be in all-cases. Moderation in all things. I used that approach for 10+ years and never once had any of the problems people claim about using inheritance for code reuse. This was likely because my needs were constrained by the use-case and by nature did not grow out of control with complexity.
My experience is the opposite. There are subtle bugs I keep running into with static function and properties causing unexpected behavior. I'm not against having static classes open by default for the sake of consistency, though my preference would be to avoid the headache altogether and just make them final by default so I won't ever have to deal with it. Would traits not solve the problem of horizontal reuse?
Hi Lynn,
I understand it's frustrating when there are bugs/unexpected behaviour, but wouldn't the (existing) ability to add the final
keyword to a class solve those issues for you, without preventing others from using the capabilities of parent/child class relationships?
Cheers
Stephen
On Fri, Jun 28, 2024 at 8:04 PM Stephen Reay php-lists@koalephant.com
wrote:
and inheritance is not meant for code reuse.
Just because code reuse in inheritance can be problematic it does not
have to be in all-cases. Moderation in all things. I used that approach for
10+ years and never once had any of the problems people claim about using
inheritance for code reuse. This was likely because my needs were
constrained by the use-case and by nature did not grow out of control with
complexity.My experience is the opposite. There are subtle bugs I keep running into
with static function and properties causing unexpected behavior. I'm not
against having static classes open by default for the sake of consistency,
though my preference would be to avoid the headache altogether and just
make them final by default so I won't ever have to deal with it. Would
traits not solve the problem of horizontal reuse?Hi Lynn,
I understand it's frustrating when there are bugs/unexpected behaviour,
but wouldn't the (existing) ability to add thefinal
keyword to a class
solve those issues for you, without preventing others from using the
capabilities of parent/child class relationships?Cheers
Stephen
The main issue is that it's easy to mess up by default and not messing up
requires you to understand why. I prefer defensive programming, close it
and only open when it's really required. If there's legit scenarios where
you need inheritance in a static context the requirement could be an "open"
keyword or removing it being final, we can't do it the other way around
without massive BC break.
Hi Ayesh,
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?
I believe Tim already answered this, and I understood his reasoning to
be that keywords are used when they modify behaviour in a way that is
meaningful for the consumer of that class. Or to put it another way,
attributes are purely informational. For me personally, introducing an
attribute never crossed my mind, and since we already have the keyword
in the language performing a similar function in PHP, and other
languages already, it seems nonsense to contemplate anything else.- Can a subclass extend a static parent class without using the
static
keyword in the subclass? This will avoid a lot of BC issues
if a library decides to declare classes as static.
No, a static parent implies a static child, but implied or not, it must
still be specified explicitly. I may need to clarify that in the RFC, so
thanks for the question.- Are there any opt-out mechanisms for subclasses?
Not sure what you mean exactly, but if you mean, can a static subclass
suddenly become non-static, the answer is no.Again thanks for the
question, as this is also something I had no previously considered.- Can you mark interfaces, abstract classes, and Enums as static?
It seems others avoided addressing this question, and honestly I was not
really sure where to go with this one. What would it mean for an enum to
be static? I thought the whole point was we can type a group of values,
but static classes have no meaning within the type system, so I cannot
see the application.
As for abstract classes, the current version of the RFC (1.2) now
declares static mutually exclusive with abstract, so the answer there is
also no.
For interfaces, I haven't given this a great deal of thought. In
principle I don't think a static interface is especially useful, but I
could be wrong about this. Nevertheless, it is not something I intend
for this RFC, since even just static classes already have their
detractors, and expanding its scope any further is probably placing it
further in danger of rejection. So for now, the answer is also no, but
static interfaces seem like a reasonable extension to this work if there
is interest in future.
Cheers,
Bilge
Hi
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?
I believe Tim already answered this, and I understood his reasoning to
be that keywords are used when they modify behaviour in a way that is
meaningful for the consumer of that class. Or to put it another way,
attributes are purely informational. For me personally, introducing an
You understood that correctly.
The forward compatibility argument brought forward by the other
participants is not really useful either, because consider the following:
#[StaticClass]
class Foo {
public static function myFunc() { }
}
class Bar extends Foo {
public function myNonStaticFunc() { }
}
This would work fine in PHP 8.3, but break when upgrading to PHP 8.4! By
using a keyword it is guaranteed that the code only runs on PHP versions
that will reliably enforce all the constraints, preventing this gotcha
during a PHP version upgrade.
Best regards
Tim Düsterhus
Le 24 juin 2024 à 01:10, Bilge bilge@scriptfusion.com a écrit :
Hi Internals!
I am pleased to present my first RFC: Static class https://wiki.php.net/rfc/static_class.
This work is based on the previous discussion thread on this list of the same name, and hopefully captured all the relevant details, notwithstanding anything unanticipated that may present itself during the implementation. Let me know if you feel anything important has been missed. I am aware it omits to mention specifics about messages so emitted when runtime or compile-time errors occur, but I anticipate this can be hashed out in the PR, unless consensus indicates otherwise.
I am aware this idea is not supported by everyone, but there seemed to be enough positive voices for it to be worth a shot. I'd like to get a better idea of where people might stand when it comes down to a vote, now there is a formal RFC, so we know whether it's worth completing the implementation, although any sentiments so proffered are of course not a commitment to vote any particular way and nobody should feel compelled to speak to that unless comfortable. Looking forward to feedback!
Cheers,
Bilge
Hi,
A general remark: I appreciate that a static class does not impose arbitrary restrictions (like: implicitly final
) on the class beyond what is meaningful for staticness. On the other side, I don’t think that we should support markers that are technically possible, but semantically meaningless, like the readonly
marker on class.
Some more specific remarks:
-
In the intro: “A static class is a class whose members (properties and methods) are all static”. One of the most important point is missing, namely: It is meaningless for a static class to have instances.
-
In the “Proposal” section, it should be stated explicitly that any attempt to construct an instance, not only with
new
, but also with any of theReflectionClass::newInstance*()
methods, or withunserialize()
, or with whatever other mean, shall fail.
Should a static class be marked readonly
or abstract
? I think not, because those have no real semantic meaning for static class; their effects on static members are only consequences of their intended meaning on non-static class:
-
Unless/until the
readonly
marker may be applied to static properties, the only effect of such a keyword, is that it would prevent the creation of static properties. I don’t know if that restriction is useful, but in case it would be used for that purpose, it would be hijacking thereadonly
marker for a something it wasn’t intended for. -
The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.
The RFC says that a static class may extend a class not explicitly marked as static, but with no instance member. This is not sound, because a class with no instance members is not necessarily static. The most obvious example is stdClass
(which has no member at all, even if their instances may have properties).
—Claude
I am pleased to present my first RFC: Static class
To recap my opinion from the other thread:
I generally support the idea to have a label to slap on all-static
classes, to make that contract more explicit.
The goal is not to promote a specific use of the language, but to add
clarity to what already exists.
Since my last response on the other thread, I warmed up more to
namespaced floating functions, thanks Larry :)
At the same time I don't see static methods and all-static classes
fully going away soon, so I still support them having a label.
But...
Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?
I don't know that it needs to be a language keyword.
An attribute would be ok for me, or even just a doc tag with phpstan.
In fact maybe a feature request with phpstan could be a starting point.
One question our razor cannot answer is whether static member declarations still require the static keyword in a static class. Marking a class readonly makes marking properties with the same optional, thus one might argue static should follow suit. However, I opine it should not. Unlike readonly, which typically applies to properties declared near the head of the class (by convention) where the same mark is also applied, static members appear throughout the full length of the class body. That is, it should be apparent when jumping anywhere into a static class that its members are static, without having to check the class declaration.
I prefer that the static keyword be required on the members.
This supports the common use case of incremental refactoring, where
methods are moved from one class to another, or a git merge where one
branch adds the class-level static keyword, while another commit adds
another method.
We cannot remove features from a static class that would otherwise be present in a standard class.
I think I get the intent of this statement, but I don't really vibe
with the wording.
I would say we should limit the scope of a modifier keyword to its essence.
And we should not remove features that are already being used in
classes that would naturally qualify for the class-level static
modifier.
Hi,
Hi Claude! I really appreciate your feedback. Everything you highlighted
is an important point that will be included in the RFC!
A general remark: I appreciate that a static class does not impose arbitrary restrictions (like: implicitlyfinal
) on the class beyond what is meaningful for staticness. On the other side, I don’t think that we should support markers that are technically possible, but semantically meaningless, like thereadonly
marker on class.
Great point,readonly
andstatic
should be mutually exclusive and
generate a compile-time error, sincereadonly static
properties are
not supported.
Some more specific remarks:
In the intro: “A static class is a class whose members (properties and methods) are all static”. One of the most important point is missing, namely: It is meaningless for a static class to have instances.
I thought that was covered off, but I'll see if I can word it better.In the “Proposal” section, it should be stated explicitly that any attempt to construct an instance, not only with
new
, but also with any of theReflectionClass::newInstance*()
methods, or withunserialize()
, or with whatever other mean, shall fail.
Great point, I'll include that detail.I think we're also missing a
similar detail with respect to dynamic properties, which should of
course also be forbidden.
Should a static class be markedreadonly
orabstract
? I think not, because those have no real semantic meaning for static class; their effects on static members are only consequences of their intended meaning on non-static class:Unless/until the
readonly
marker may be applied to static properties, the only effect of such a keyword, is that it would prevent the creation of static properties. I don’t know if that restriction is useful, but in case it would be used for that purpose, it would be hijacking thereadonly
marker for a something it wasn’t intended for.
Agree, as above, we'll make them mutually exclusive.The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.
I tend to find inheritance is not a very useful concept in static
contexts, but others have already pointed out that some have found uses
for it. Due to my lack of experience I cannot confidently say that
abstract static
has no value, but you make a compelling argument.
Happy to add a similar mutual exclusivity prohibition for this keyword
too, unless and until someone protests it with an equally compelling
argument to the contrary.
The RFC says that a static class may extend a class not explicitly marked as static, but with no instance member. This is not sound, because a class with no instance members is not necessarily static. The most obvious example isstdClass
(which has no member at all, even if their instances may have properties).
Do you mean it is not simply sufficient for a class to be regarded as
implicitly static by virtue of the fact that it has no instance members?
I'm not sure I agree, but I may be missing something. If we extend
stdClass
then we gain nothing, and our class so extending it can still
be safely marked static, can it not? Please elaborate so I might
understand better.
Kind regards,
Bilge
Hi,
Hi Claude! I really appreciate your feedback. Everything you highlighted is an important point that will be included in the RFC!
A general remark: I appreciate that a static class does not impose arbitrary restrictions (like: implicitly
final
) on the class beyond what is meaningful for staticness. On the other side, I don’t think that we should support markers that are technically possible, but semantically meaningless, like thereadonly
marker on class.Great point,
readonly
andstatic
should be mutually exclusive and generate a compile-time error, sincereadonly static
properties are not supported.Some more specific remarks:
- In the intro: “A static class is a class whose members (properties and methods) are all static”. One of the most important point is missing, namely: It is meaningless for a static class to have instances.
I thought that was covered off, but I'll see if I can word it better.
- In the “Proposal” section, it should be stated explicitly that any attempt to construct an instance, not only with
new
, but also with any of theReflectionClass::newInstance*()
methods, or withunserialize()
, or with whatever other mean, shall fail.Great point, I'll include that detail. I think we're also missing a similar detail with respect to dynamic properties, which should of course also be forbidden.
Should a static class be marked
readonly
orabstract
? I think not, because those have no real semantic meaning for static class; their effects on static members are only consequences of their intended meaning on non-static class:
- Unless/until the
readonly
marker may be applied to static properties, the only effect of such a keyword, is that it would prevent the creation of static properties. I don’t know if that restriction is useful, but in case it would be used for that purpose, it would be hijacking thereadonly
marker for a something it wasn’t intended for.Agree, as above, we'll make them mutually exclusive.
- The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.I tend to find inheritance is not a very useful concept in static contexts, but others have already pointed out that some have found uses for it. Due to my lack of experience I cannot confidently say that
abstract static
has no value, but you make a compelling argument. Happy to add a similar mutual exclusivity prohibition for this keyword too, unless and until someone protests it with an equally compelling argument to the contrary.The RFC says that a static class may extend a class not explicitly marked as static, but with no instance member. This is not sound, because a class with no instance members is not necessarily static. The most obvious example is
stdClass
(which has no member at all, even if their instances may have properties).Do you mean it is not simply sufficient for a class to be regarded as implicitly static by virtue of the fact that it has no instance members? I'm not sure I agree, but I may be missing something. If we extend
stdClass
then we gain nothing, and our class so extending it can still be safely marked static, can it not? Please elaborate so I might understand better.Kind regards,
Bilge
Hey Bilge,
Do you mean it is not simply sufficient for a class to be regarded as implicitly static by virtue of the fact that it has no instance members? I'm not sure I agree, but I may be missing something. If we extend
stdClass
then we gain nothing, and our class so extending it can still be safely marked static, can it not? Please elaborate so I might understand better.
I think it is sound in theory, but in practice, it will be a foot gun.
Imagine if you were to take my HTTP code library and make something
static from it. Later, I added an instance member. Now, when you
upgrade, everything starts crashing because of one little change
unrelated to your code.
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?
From my perspective that would create much confusion among every PHP developer who has not committed to memory when to use static
as a class keyword and when to use it as an attribute.
Given the concept already exists in keywords I would strongly argue that it makes no sense to introduce as an attributes in core PHP.
Attributes are great for concepts new to PHP, IMO, but not for existing concepts already part of PHP implemented with keywords.
- The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.
Given a primary purpose for being able to declare a class static
is to signal intent, disallowing abstract static
classes seems at odds with that goal.
Of course it is currently true that static
methods of abstract
classes can be called from outside a class and its class hierarchy, so if we allow declaring abstract static
classes then it would never in the future be possible to lock down calls of static
methods to those abstract
classes.
So IMO it would be better to disallow calling static
methods from outside a declared abstract static
class and its inheritance hierarchy as part of this RFC. That would be backward compatible since there are currently no classes that are declared in that manner. Doing otherwise would force those who want to declare a class as both static
and abstract
to have to make a choice rather than being able to signal their full intent. Which brings us back to the "implied" vs. "explicitly declared" bifurcation I mentioned in a prior email.
BTW, I am assuming it is technically possible to disallow calling methods for classes declared both abstract
and static
without considerable difficulty in implementation and without creating a significant drain on performance.
-Mike
P.S. I would argue the same for readonly static
properties, but as that seems those would require an involved discussion about the exact rules to implement I am demurring on that topic.
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?From my perspective that would create much confusion among every PHP developer who has not committed to memory when to use
static
as a class keyword and when to use it as an attribute.Given the concept already exists in keywords I would strongly argue that it makes no sense to introduce as an attributes in core PHP.
Attributes are great for concepts new to PHP, IMO, but not for existing concepts already part of PHP implemented with keywords.
- The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.Given a primary purpose for being able to declare a class
static
is to signal intent, disallowingabstract static
classes seems at odds with that goal.Of course it is currently true that
static
methods ofabstract
classes can be called from outside a class and its class hierarchy, so if we allow declaringabstract static
classes then it would never in the future be possible to lock down calls ofstatic
methods to thoseabstract
classes.So IMO it would be better to disallow calling
static
methods from outside a declaredabstract static
class and its inheritance hierarchy as part of this RFC. That would be backward compatible since there are currently no classes that are declared in that manner. Doing otherwise would force those who want to declare a class as bothstatic
andabstract
to have to make a choice rather than being able to signal their full intent. Which brings us back to the "implied" vs. "explicitly declared" bifurcation I mentioned in a prior email.BTW, I am assuming it is technically possible to disallow calling methods for classes declared both
abstract
andstatic
without considerable difficulty in implementation and without creating a significant drain on performance.-Mike
P.S. I would argue the same for
readonly static
properties, but as that seems those would require an involved discussion about the exact rules to implement I am demurring on that topic.
Hi Mike,
So IMO it would be better to disallow calling
static
methods from outside a declaredabstract static
class
Can you explain what you mean by this, or more specifically the "why". What (implied wrong/bad) scenario are you trying to prevent, by disallowing a static method on an abstract class to be called?
As you point out, it's already possible to call (public) static methods on abstract classes, the same as it's possible to call (public) static methods without instantiating a regular class.
So why should static abstract classes be different? If the static method shouldn't be called publicly, it shouldn't be public. Are you suggesting that public static methods shouldn't be callable on any abstract class? If so, this sounds like a huge BC break, and if not, it sounds like a confusing "if-then-but-why" scenario.
I agree that the static
keyword is a much better fit here, however there is one other aspect here that may come into it (as much as I prefer the keyword approach): the Attribute approach is backwards compatible (with a polyfill) to let code using this feature also run on previous PHP releases. Given that this is mostly intended as a way to signal intent about a pattern that's already in use, this may be significant for library authors.
Personally (as a library author) I don't think that ability is worth the weirdness of an attribute vs a keyword, but it may be more important for others who are voting, and I'd rather have the feature with slightly odd syntax rather than not at all.
Cheers
Stephen
Hi guys,
Given a primary purpose for being able to declare a class `static` is to *signal intent*, disallowing `abstract static` classes seems at odds with that goal.
What is the /intent/ of abstract static
? How is such intent different
from just static
?
I agree that the
static
keyword is a much better fit here, however
there is one other aspect here that may come into it (as much as I
prefer the keyword approach): the Attribute approach is backwards
compatible (with a polyfill) to let code using this feature also run
on previous PHP releases. Given that this is mostly intended as a way
to signal intent about a pattern that's already in use, this may be
significant for library authors.Personally (as a library author) I don't think that ability is worth
the weirdness of an attribute vs a keyword, but it may be more
important for others who are voting, and I'd rather have the feature
with slightly odd syntax rather than not at all.
When I first saw the proposal to use an attribute instead of the
keyword, I thought it absurd, but this idea has now been entertained by
three people, and for the first time I have seen a compelling argument
in favour of (early adoption). I must admit, I was too quick to judge
this one. I had not considered that libraries will still not be able to
use thestatic
modifier with classes unless and until they drop
support for PHP < 8.4, which may take a while! Of course, it is still of
real benefit to first-party proprietary projects whom have upgraded.
Nevertheless, the allure of early adoption is curious, and made me
wonder whether we could do both, just to support early adoption in a
backwards-compatible manner. However, this would be unprecedented and
most likely not accepted; never before has the same feature been
implemented two ways just to appease early adopters. I think the best
compromise would be, for anyone so eager, to implement such support in
community tools, e.g. PHPStan. That is, it should be perfectly possible
to enforce the core semantics of the static class feature with a
userland attribute and the necessary logic in static analysis tools,
provided the library is well behaved and doesn't do anything too weird
with variable variables, references, reflection orunserialize()
to
deliberately circumvent the restriction.
Cheers,
Bilge
Hi,
Hi guys,
Given a primary purpose for being able to declare a class
static
is to signal intent, disallowingabstract static
classes seems at odds with that goal.
What is the intent ofabstract static
? How is such intent different from juststatic
?
Sorry I should have been clearer. It isn't that abstract
represents an intent, it's that adding static
is mostly about conveying intent - and thus there's no technical reason that any existing class with only static members can't be marked as a static class, so why introduce an artificial barrier if that class happens to already be abstract?
It's already possible to have a class with only static members, that is abstract, and call the public static methods of it. It's also possible to have a class that partially implements an interface that has static methods on it. Unless your RFC is going to propose preventing calling static methods on all abstract classes it's a needless complication when there's no technical reason to do so.
I agree that the
static
keyword is a much better fit here, however there is one other aspect here that may come into it (as much as I prefer the keyword approach): the Attribute approach is backwards compatible (with a polyfill) to let code using this feature also run on previous PHP releases. Given that this is mostly intended as a way to signal intent about a pattern that's already in use, this may be significant for library authors.Personally (as a library author) I don't think that ability is worth the weirdness of an attribute vs a keyword, but it may be more important for others who are voting, and I'd rather have the feature with slightly odd syntax rather than not at all.
When I first saw the proposal to use an attribute instead of the keyword, I thought it absurd, but this idea has now been entertained by three people, and for the first time I have seen a compelling argument in favour of (early adoption). I must admit, I was too quick to judge this one. I had not considered that libraries will still not be able to use thestatic
modifier with classes unless and until they drop support for PHP < 8.4, which may take a while! Of course, it is still of real benefit to first-party proprietary projects whom have upgraded. Nevertheless, the allure of early adoption is curious, and made me wonder whether we could do both, just to support early adoption in a backwards-compatible manner. However, this would be unprecedented and most likely not accepted; never before has the same feature been implemented two ways just to appease early adopters. I think the best compromise would be, for anyone so eager, to implement such support in community tools, e.g. PHPStan. That is, it should be perfectly possible to enforce the core semantics of the static class feature with a userland attribute and the necessary logic in static analysis tools, provided the library is well behaved and doesn't do anything too weird with variable variables, references, reflection orunserialize()
to deliberately circumvent the restriction.
Yes it should be possible to use a user land attribute or phpdoc tag or what have, but that's already true. You've essentially just made a case against your own RFC - that it can mostly be done already in userland.
The entire appeal of a builtin attribute would be that it's something you could apply now (as in today, June 2024) and know that it won't break anything, while having some {compile,run} time benefits in later versions (e.g. enforcing static-only, and inability to instantiate).
Like I said, I much prefer the keyword syntax - but I also recognise that others may have different priorities in terms of supporting older language versions, which is why I think that aspect is worth consideration (perhaps a secondary vote, or an informal vote to gauge consensus?), because too many good RFCs get rejected over small details.
Cheers,
Bilge
Cheers
Stephen
Hi
Like I said, I much prefer the keyword syntax - but I also recognise that others may have different priorities in terms of supporting older language versions, which is why I think that aspect is worth consideration (perhaps a secondary vote, or an informal vote to gauge consensus?), because too many good RFCs get rejected over small details.
Syntax is absolutely not a small detail. It's the most user-visible part
of a language feature that is not just a new part in the standard
library. And that is probably the reason why it's the most hotly debated
part of any new language feature that is proposed.
As said in my previous email, I strongly oppose inventing new syntax and
instead borrow syntax from existing (related) features as much as
possible. An example that comes to my mind would be the initial
brace-based syntax for the clone-with RFC that has since been replaced
by array-style syntax that should be immediately understandable by any
PHP programmer. PHP should continue to look and feel like PHP.
Best regards
Tim Düsterhus
Nevertheless, the allure of early adoption is curious, and made me wonder whether we could do both, just to support early adoption in a backwards-compatible manner.
And that is probably the best solution I've heard regarding this quandary.
It could potentially apply with other keywords in the future as well.
#fwiw
-Mike
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?From my perspective that would create much confusion among every PHP developer who has not committed to memory when to use
static
as a class keyword and when to use it as an attribute.Given the concept already exists in keywords I would strongly argue that it makes no sense to introduce as an attributes in core PHP.
Attributes are great for concepts new to PHP, IMO, but not for existing concepts already part of PHP implemented with keywords.
- The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.Given a primary purpose for being able to declare a class
static
is to signal intent, disallowingabstract static
classes seems at odds with that goal.Of course it is currently true that
static
methods ofabstract
classes can be called from outside a class and its class hierarchy, so if we allow declaringabstract static
classes then it would never in the future be possible to lock down calls ofstatic
methods to thoseabstract
classes.So IMO it would be better to disallow calling
static
methods from outside a declaredabstract static
class and its inheritance hierarchy as part of this RFC. That would be backward compatible since there are currently no classes that are declared in that manner. Doing otherwise would force those who want to declare a class as bothstatic
andabstract
to have to make a choice rather than being able to signal their full intent. Which brings us back to the "implied" vs. "explicitly declared" bifurcation I mentioned in a prior email.BTW, I am assuming it is technically possible to disallow calling methods for classes declared both
abstract
andstatic
without considerable difficulty in implementation and without creating a significant drain on performance.-Mike
P.S. I would argue the same for
readonly static
properties, but as that seems those would require an involved discussion about the exact rules to implement I am demurring on that topic.Hi Mike,
So IMO it would be better to disallow calling
static
methods from outside a declaredabstract static
classCan you explain what you mean by this, or more specifically the "why". What (implied wrong/bad) scenario are you trying to prevent, by disallowing a static method on an abstract class to be called?
As you point out, it's already possible to call (public) static methods on abstract classes, the same as it's possible to call (public) static methods without instantiating a regular class.
So why should static abstract classes be different? If the static method shouldn't be called publicly, it shouldn't be public. Are you suggesting that public static methods shouldn't be callable on any abstract class? If so, this sounds like a huge BC break, and if not, it sounds like a confusing "if-then-but-why" scenario.
Thank you for the question.
I was not specifically advocating static
methods to be disallowed to be called on an abstract
class. I was instead addressing the desire by another list member to have classes declared static
not also be able to be declared abstract.
That person made the argument that if 'abstract static` did not actually have any effect then it should not be allowed by the RFC.
What affect are we talking about? If it is both abstract
and static
then it would seem to me the only effect such a declaration could have would be to disallow the calling of static methods using the named abstract static class, e.g.:
abstract static class Base {
static public foo() {
echo "foo() called\n"
}
}
static class Concrete extends Base {}
Concrete::foo(); // works
Base::foo(); // fails
My only real argument for disallowing static method calls on abstract static classes is that if we didn't do so initially we would never be able to disallow because of BC.
In summary, my argument was really only about ensuring we allow "abstract static" declaration so developers can signal intent and also to address the objections of the other list member. But if given the option, I think it would be good to disallow calling static methods on abstract static classes if only to reserve the right to allow in the future vs. closing that door immediately. Still, that latter is not the hill for me to die on.
I agree that the
static
keyword is a much better fit here, however there is one other aspect here that may come into it (as much as I prefer the keyword approach): the Attribute approach is backwards compatible (with a polyfill) to let code using this feature also run on previous PHP releases. Given that this is mostly intended as a way to signal intent about a pattern that's already in use, this may be significant for library authors.
Well, as previously stated, I think that would be confusing.
Though I do see your reasoning for wanting it to be an attribute. However...
Personally (as a library author) I don't think that ability is worth the weirdness of an attribute vs a keyword, but it may be more important for others who are voting, and I'd rather have the feature with slightly odd syntax rather than not at all.
I too am not convinced that the ongoing confusion would be better than the temporary need to support older versions of PHP with the same source file.
Given that a build step could address the syntax there are certainly other new language features that require developers to bifurcate their libraries to support different versions, why make this one unique?
That said, it could be a voting option for the RFC?
-Mike
- Why is it a class-level flag and not an attribute (similar to the
#[Override]
attribute in PHP 8.3) ?From my perspective that would create much confusion among every PHP developer who has not committed to memory when to use
static
as a class keyword and when to use it as an attribute.Given the concept already exists in keywords I would strongly argue that it makes no sense to introduce as an attributes in core PHP.
Attributes are great for concepts new to PHP, IMO, but not for existing concepts already part of PHP implemented with keywords.
- The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.Given a primary purpose for being able to declare a class
static
is to signal intent, disallowingabstract static
classes seems at odds with that goal.Of course it is currently true that
static
methods ofabstract
classes can be called from outside a class and its class hierarchy, so if we allow declaringabstract static
classes then it would never in the future be possible to lock down calls ofstatic
methods to thoseabstract
classes.So IMO it would be better to disallow calling
static
methods from outside a declaredabstract static
class and its inheritance hierarchy as part of this RFC. That would be backward compatible since there are currently no classes that are declared in that manner. Doing otherwise would force those who want to declare a class as bothstatic
andabstract
to have to make a choice rather than being able to signal their full intent. Which brings us back to the "implied" vs. "explicitly declared" bifurcation I mentioned in a prior email.BTW, I am assuming it is technically possible to disallow calling methods for classes declared both
abstract
andstatic
without considerable difficulty in implementation and without creating a significant drain on performance.-Mike
P.S. I would argue the same for
readonly static
properties, but as that seems those would require an involved discussion about the exact rules to implement I am demurring on that topic.Hi Mike,
So IMO it would be better to disallow calling
static
methods from outside a declaredabstract static
classCan you explain what you mean by this, or more specifically the "why". What (implied wrong/bad) scenario are you trying to prevent, by disallowing a static method on an abstract class to be called?
As you point out, it's already possible to call (public) static methods on abstract classes, the same as it's possible to call (public) static methods without instantiating a regular class.
So why should static abstract classes be different? If the static method shouldn't be called publicly, it shouldn't be public. Are you suggesting that public static methods shouldn't be callable on any abstract class? If so, this sounds like a huge BC break, and if not, it sounds like a confusing "if-then-but-why" scenario.
Thank you for the question.
I was not specifically advocating
static
methods to be disallowed to be called on anabstract
class. I was instead addressing the desire by another list member to have classes declaredstatic
not also be able to be declaredabstract.
That person made the argument that if 'abstract static` did not actually have any effect then it should not be allowed by the RFC.
What affect are we talking about? If it is both
abstract
andstatic
then it would seem to me the only effect such a declaration could have would be to disallow the calling of static methods using the named abstract static class, e.g.:abstract static class Base {
static public foo() {
echo "foo() called\n"
}
}
static class Concrete extends Base {}Concrete::foo(); // works
Base::foo(); // failsMy only real argument for disallowing static method calls on abstract static classes is that if we didn't do so initially we would never be able to disallow because of BC.
In summary, my argument was really only about ensuring we allow "abstract static" declaration so developers can signal intent and also to address the objections of the other list member. But if given the option, I think it would be good to disallow calling static methods on abstract static classes if only to reserve the right to allow in the future vs. closing that door immediately. Still, that latter is not the hill for me to die on.
I agree that the
static
keyword is a much better fit here, however there is one other aspect here that may come into it (as much as I prefer the keyword approach): the Attribute approach is backwards compatible (with a polyfill) to let code using this feature also run on previous PHP releases. Given that this is mostly intended as a way to signal intent about a pattern that's already in use, this may be significant for library authors.Well, as previously stated, I think that would be confusing.
Though I do see your reasoning for wanting it to be an attribute. However...
Personally (as a library author) I don't think that ability is worth the weirdness of an attribute vs a keyword, but it may be more important for others who are voting, and I'd rather have the feature with slightly odd syntax rather than not at all.
I too am not convinced that the ongoing confusion would be better than the temporary need to support older versions of PHP with the same source file.
Given that a build step could address the syntax there are certainly other new language features that require developers to bifurcate their libraries to support different versions, why make this one unique?
That said, it could be a voting option for the RFC?
-Mike
Hi Mike,
This is an example of code that works today (and all the way back to 5.0): https://3v4l.org/4EKo2
The class hierarchy embody the type of classes this RFC is about: only static members, no instantiation.
The implemented methods can be called statically, regardless of whether the class they're implemented in is abstract or not. The abstract methods cannot be called directly.
So these classes would be a candidate for the static
class keyword (or Attribute) - except they can't, if calls to implemented methods on abstract classes are disallowed. Because the Base::a() method has been publicly callable, for potentially as long as <checks notes> 20 years next month.
My point here is that if someone wants to prohibit calling public static methods on abstract classes with the static keyword, that's going be inconsistent with how it's worked for the last 20 years (i.e. on classes that were 'static' in intent but not syntactically), or if it applies the change everywhere it's going to be a BC break.
Re: attribute vs keyword,
Like I said - I'm not personally in favour of the attribute approach; I'm simply making the point (playing devils advocate if you will) that by the very nature of how attributes work, they're more friendly to supporting older versions of the language with a single code base. If the general consensus is that it isn't a concern, great. But this wouldn't be the first time we've seen a relatively minor syntax choice derail an otherwise useful RFC.
Cheers
Stephen
Hi Stephen,
This is an example of code that works today (and all the way back to 5.0): https://3v4l.org/4EKo2 https://3v4l.org/4EKo2
The class hierarchy embody the type of classes this RFC is about: only static members, no instantiation.
The implemented methods can be called statically, regardless of whether the class they're implemented in is abstract or not. The abstract methods cannot be called directly.
So these classes would be a candidate for the
static
class keyword (or Attribute) - except they can't, if calls to implemented methods on abstract classes are disallowed. Because the Base::a() method has been publicly callable, for potentially as long as <checks notes> 20 years next month.My point here is that if someone wants to prohibit calling public static methods on abstract classes with the static keyword, that's going be inconsistent with how it's worked for the last 20 years (i.e. on classes that were 'static' in intent but not syntactically), or if it applies the change everywhere it's going to be a BC break.
It seems what you are asking about is downstream from the reason I stated that I made the argument in the first place, which AFAICT you did not acknowledge. That leaves me unsure of your position on a precursor topic to your above stated objections.
As stated, my primary (initial) reason for arguing that abstract static
should disallow calling static methods using the class name of the static class marked abstract — as my earlier example of calling Base::foo()
illustrated— was in response to the argument against allowing
abstractwith
static` because — in Claude's words — it would "have no real semantic meaning for static class; their effects on static members are only consequences of their intended meaning on non-static class." I have copied his complete words on that topic below:
Should a static class be marked
abstract
? I think not, because those have no real semantic meaning for static class; their effects on static members are only consequences of their intended meaning on non-static class:
- The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.
Thus my argument supporting abstract static
was addressing his objections by suggesting that we could have an abstract static class
declaration disallow calling any of the static
methods of the class using the name of the class declared abstract
given that it would in fact not cause any BC breaks with untouched code.
Before you repeat your objections to disallowing, permit me to ask you which of the following upstream arguments you are making? Is your position that we should:
- Disallow
abstract
onstatic
as Claude argued? - Allow
abstract static
in spite of Claude's argument against it?
Also, if you answer "2. Allow abstract static
" then please how do you address Claude's objections?
Once I am clear of your position on two above I will address your objections stated in your most recent response to me, which I quoted at the beginning of this email. Thank you in advance for the clarity.
-Mike
Hi Stephen,
This is an example of code that works today (and all the way back to 5.0): https://3v4l.org/4EKo2
The class hierarchy embody the type of classes this RFC is about: only static members, no instantiation.
The implemented methods can be called statically, regardless of whether the class they're implemented in is abstract or not. The abstract methods cannot be called directly.
So these classes would be a candidate for the
static
class keyword (or Attribute) - except they can't, if calls to implemented methods on abstract classes are disallowed. Because the Base::a() method has been publicly callable, for potentially as long as <checks notes> 20 years next month.My point here is that if someone wants to prohibit calling public static methods on abstract classes with the static keyword, that's going be inconsistent with how it's worked for the last 20 years (i.e. on classes that were 'static' in intent but not syntactically), or if it applies the change everywhere it's going to be a BC break.
It seems what you are asking about is downstream from the reason I stated that I made the argument in the first place, which AFAICT you did not acknowledge. That leaves me unsure of your position on a precursor topic to your above stated objections.
As stated, my primary (initial) reason for arguing that
abstract static
should disallow calling static methods using the class name of the static class marked abstract — as my earlier example of callingBase::foo()
illustrated— was in response to the argument against allowing
abstractwith
static` because — in Claude's words — it would "have no real semantic meaning for static class; their effects on static members are only consequences of their intended meaning on non-static class." I have copied his complete words on that topic below:Should a static class be marked
abstract
? I think not, because those have no real semantic meaning for static class; their effects on static members are only consequences of their intended meaning on non-static class:
- The main purpose of the
abstract
keyword is to prevent a class to be instantiated, which (in case of static class) is more semantically described by thestatic
marker. Beyond that, it just allows to declare a method that, if implemented by a subclass, should have a compatible signature. Most notably, it does not prevent the other static members of the class to be used directly.Thus my argument supporting
abstract static
was addressing his objections by suggesting that we could have anabstract static class
declaration disallow calling any of thestatic
methods of the class using the name of the class declaredabstract
given that it would in fact not cause any BC breaks with untouched code.Before you repeat your objections to disallowing, permit me to ask you which of the following upstream arguments you are making? Is your position that we should:
- Disallow
abstract
onstatic
as Claude argued?- Allow
abstract static
in spite of Claude's argument against it?Also, if you answer "2. Allow
abstract static
" then please how do you address Claude's objections?Once I am clear of your position on two above I will address your objections stated in your most recent response to me, which I quoted at the beginning of this email. Thank you in advance for the clarity.
-Mike
Hi Mike,
To answer your question: I believe abstract static
should be allowed, because the "objection" mis-characterises a particular aspect of them as an unintended consequence, when there's evidence to show that's not that case.
Claude essentially dismisses the use of abstract static methods:
only consequences of their intended meaning on non-static class
In v5.2 a strict standards notice was added regarding the use of abstract static methods in classes. No notice was ever shown when they're used in interfaces. In v7 this notice was removed (via https://wiki.php.net/rfc/reclassify_e_strict#abstract_static_methods) because, as Nikita noted at the time:
We currently allow the use of abstract static functions in interfaces, as such it is inconsistent to not allow them as abstract methods. By using late static binding a method in the abstract class can reasonably depend on the existence of a static method in a superclass.
That to me says this is an intended feature, and not an unintended consequence.
Cheers
Stephen
Hi Mike,
To answer your question: I believe
abstract static
should be allowed, because the "objection" mis-characterises a particular aspect of them as an unintended consequence, when there's evidence to show that's not that case.Claude essentially dismisses the use of abstract static methods:
only consequences of their intended meaning on non-static class
In v5.2 a strict standards notice was added regarding the use of abstract static methods in classes. No notice was ever shown when they're used in interfaces. In v7 this notice was removed (via https://wiki.php.net/rfc/reclassify_e_strict#abstract_static_methods https://wiki.php.net/rfc/reclassify_e_strict#abstract_static_methods) because, as Nikita noted at the time:
Thank you for elaborating.
We are on the same page here as I too think abstract static
should be allowed when declaring a class
We currently allow the use of abstract static functions in interfaces, as such it is inconsistent to not allow them as abstract methods. By using late static binding a method in the abstract class can reasonably depend on the existence of a static method in a superclass.
That to me says this is an intended feature, and not an unintended consequence.
Before I address this and your other comments, please understand that I do not see this as a huge issue either way, but I do want my argument to be understood. If my argument on this does not win the day, I will not lament it in any way.
As an aside, I had never seen interfaces used that way and found it surprising. Obviously I missed when Nikita made that claim.
As for "an intended feature, and not an unintended consequence," when I was in university they drilled the idea of a sunken cost into me to the point I am a true believer. IOW, make the best decision moving forward vs. doubling down on bad decisions.
Note that I am not saying Nikita's was a bad decision (or a good one) just that the existence of a prior decision should not color making the best decision moving forward.
I am curious, do you know of real-world userland code that is actually configured as your example that would be negatively affected by disallowing static methods calls?
This is an example of code that works today (and all the way back to 5.0): https://3v4l.org/4EKo2 https://3v4l.org/4EKo2The class hierarchy embody the type of classes this RFC is about: only static members, no instantiation.
The implemented methods can be called statically, regardless of whether the class they're implemented in is abstract or not. The abstract methods cannot be called directly.
Understood, but I do not see how interfaces or instantiation or abstract method are relevant to the discussion. They all seem orthogonal to me.
So these classes would be a candidate for the
static
class keyword (or Attribute) - except they can't, if calls to implemented methods on abstract classes are disallowed. Because the Base::a() method has been publicly callable, for potentially as long as <checks notes> 20 years next month.
While it may be true that it has been that way, disallowing static methods
from being called using abstract static
classes would not be a BC break because it was previously impossible to declare a class as static
let alone abstract static
.
Further, there are often new features with constraints that result in developer not being "to do what they have been able to do for 20 years" because, looking forward, those constraints make more sense than not having those constraints.
Take a look at readonly
properties. They must be typed, but I could have used the same argument against that saying "We've always been able to have untyped properties so readonly should not have to be typed."[1] I'd say requiring them to be typed was a win, though, regardless of past property capabilities.
I'm not claiming necessarily that disallowing calling static
methods on a abstract static
class is a best practice, but I am saying that "we've been able to do it with similar syntax for a long time" is not a particularly compelling argument if disallowing is a better approach.
As another aside, assuming everyone agrees on what a best practice is for a given case, I doubt anyone would object to a constraint that forced developers to follow that best practice vs. allowing them to write less ideal code.
My point here is that if someone wants to prohibit calling public static methods on abstract classes with the static keyword, that's going be inconsistent with how it's worked for the last 20 years (i.e. on classes that were 'static' in intent but not syntactically),
Back to sunken cost, does it make more sense to only give developers who want to disallow using static methods for their abstract static
classes access to @internal docblock
— which I argued against elsewhere in this thread — and let Hyrum's Law take over, OR do we enable them to disallow calling those static
methods from the abstract
class itself?
More importantly, IF we do not immediately disallow calling static
methods on abstract static
classes then we will never be able to disallow in the future, because of BC. But on the flip side we could later open them up for calling if we found the limitation to be problematic.
or if it applies the change everywhere it's going to be a BC break.
And to be clear, I am against BC breaks in almost all cases. So bringing that up between us is moot.
All that said, if you tell me "I don't care about closing the door on being able to disallow developers from calling static methods on abstract static
methods because prior to abstract static
classes static
methods could be called on abstract
classes in the past" I will respect that, and as I said above, it won't bother me.
My only reason for persisting is to ensure that the argument I was making was understood before it was dismissed.
-Mike
[1] Ignoring there were technical issues with allowing untyped to be readonly, which could have been gotten around somehow if the consensus was "They must be able to untyped."
Hi Mike,
To answer your question: I believe
abstract static
should be allowed, because the "objection" mis-characterises a particular aspect of them as an unintended consequence, when there's evidence to show that's not that case.Claude essentially dismisses the use of abstract static methods:
only consequences of their intended meaning on non-static class
In v5.2 a strict standards notice was added regarding the use of abstract static methods in classes. No notice was ever shown when they're used in interfaces. In v7 this notice was removed (via https://wiki.php.net/rfc/reclassify_e_strict#abstract_static_methods) because, as Nikita noted at the time:
Thank you for elaborating.
We are on the same page here as I too think
abstract static
should be allowed when declaring a classWe currently allow the use of abstract static functions in interfaces, as such it is inconsistent to not allow them as abstract methods. By using late static binding a method in the abstract class can reasonably depend on the existence of a static method in a superclass.
That to me says this is an intended feature, and not an unintended consequence.
Before I address this and your other comments, please understand that I do not see this as a huge issue either way, but I do want my argument to be understood. If my argument on this does not win the day, I will not lament it in any way.
As an aside, I had never seen interfaces used that way and found it surprising. Obviously I missed when Nikita made that claim.
As for "an intended feature, and not an unintended consequence," when I was in university they drilled the idea of a sunken cost into me to the point I am a true believer. IOW, make the best decision moving forward vs. doubling down on bad decisions.
Note that I am not saying Nikita's was a bad decision (or a good one) just that the existence of a prior decision should not color making the best decision moving forward.
I understand that, but I also think there is much value in consistency. If static methods (and abstract static methods) are supported, they should be supported consistently. There have been numerous RFCs passed that bring consistency (and thus remove developer surprise) to the language, even on features that some voters dislike so much, they'd rather the feature is intentionally difficult to use, to discourage use by other people (remember the trait constants RFC?)
I am curious, do you know of real-world userland code that is actually configured as your example that would be negatively affected by disallowing static methods calls?
Not in that specific case, no. I've seen some that uses abstract class
as a poor mans static class
(just to prevent instantiation) but not that uses abstract
to allow omitting an upstream method.
This is an example of code that works today (and all the way back to 5.0): https://3v4l.org/4EKo2
The class hierarchy embody the type of classes this RFC is about: only static members, no instantiation.The implemented methods can be called statically, regardless of whether the class they're implemented in is abstract or not. The abstract methods cannot be called directly.
Understood, but I do not see how interfaces or instantiation or abstract method are relevant to the discussion. They all seem orthogonal to me.
A class cannot contain abstract methods if it is not also marked as abstract. That's the whole point. If you prevent a static class from also being abstract, you prevent that class from partially implementing an interface (or parent class with abstract methods).
So these classes would be a candidate for the
static
class keyword (or Attribute) - except they can't, if calls to implemented methods on abstract classes are disallowed. Because the Base::a() method has been publicly callable, for potentially as long as <checks notes> 20 years next month.While it may be true that it has been that way, disallowing
static methods
from being called usingabstract static
classes would not be a BC break because it was previously impossible to declare a class asstatic
let aloneabstract static
.
Right so I'm not actually saying this is a BC break itself - I'm saying the authors of the library/code then can't adopt the static
keyword, which embodies their intent fully, because if they do so their code has a BC break (code that was previously callable, it not any more).
Further, there are often new features with constraints that result in developer not being "to do what they have been able to do for 20 years" because, looking forward, those constraints make more sense than not having those constraints.
Take a look at
readonly
properties. They must be typed, but I could have used the same argument against that saying "We've always been able to have untyped properties so readonly should not have to be typed."[1] I'd say requiring them to be typed was a win, though, regardless of past property capabilities.
I don't think the reason something has limitations should be ignored. It's not like Nikita said "we should disallow untyped properties because otherwise we have to allow them forever". It was specifically to prevent confusion due to the implicit null default on untyped properties. Also, this restriction was quite easy to work around, thanks to the mixed
type introduced in 8.0.
I'm not claiming necessarily that disallowing calling
static
methods on aabstract static
class is a best practice, but I am saying that "we've been able to do it with similar syntax for a long time" is not a particularly compelling argument if disallowing is a better approach.As another aside, assuming everyone agrees on what a best practice is for a given case, I doubt anyone would object to a constraint that forced developers to follow that best practice vs. allowing them to write less ideal code.
My point here is that if someone wants to prohibit calling public static methods on abstract classes with the static keyword, that's going be inconsistent with how it's worked for the last 20 years (i.e. on classes that were 'static' in intent but not syntactically),
Back to sunken cost, does it make more sense to only give developers who want to disallow using static methods for their
abstract static
classes access to@internal docblock
— which I argued against elsewhere in this thread — and let Hyrum's Law take over, OR do we enable them to disallow calling thosestatic
methods from theabstract
class itself?More importantly, IF we do not immediately disallow calling
static
methods onabstract static
classes then we will never be able to disallow in the future, because of BC. But on the flip side we could later open them up for calling if we found the limitation to be problematic.or if it applies the change everywhere it's going to be a BC break.
And to be clear, I am against BC breaks in almost all cases. So bringing that up between us is moot.
All that said, if you tell me "I don't care about closing the door on being able to disallow developers from calling static methods on
abstract static
methods because prior toabstract static
classesstatic
methods could be called onabstract
classes in the past" I will respect that, and as I said above, it won't bother me.
Don't care is the wrong term I think. As I've said, numerous times, I'm concerned about consistency first and foremost. If the voting powers that be deem calling a static method on an abstract class (regardless of the class's other modifers/keywords) is too much of a pearl clutching moment, and it's deprecated, I'll probably ask pretty loudly "why, what actual problem does this prevent" but I'll appreciate that it's being consistent, despite the BC break.
My only reason for persisting is to ensure that the argument I was making was understood before it was dismissed.
I think I understand your view: you're not as concerned with consistency if the alternative is something "better".
-Mike
[1] Ignoring there were technical issues with allowing untyped to be readonly, which could have been gotten around somehow if the consensus was "They must be able to untyped."
Cheers
Stephen
I think I understand your view: you're not as concerned with consistency if the alternative is something "better".
That yes, but more importantly, that deciding NOT to disallow calling static
methods on abstract static
classes is a decision for the ages that cannot be reversed later because of BC.
And with that, I think we've both beaten this horse to death so I am over and out on this topic.
-Mike
Hi
and I'd rather have the feature with slightly odd syntax rather than not at all.
Absolutely not. PHP is already odd enough as it is. We should not add
additional oddness in the interest of pushing a new screw-shaped feature
in with a sledgehammer. Any additional oddity makes it harder for Junior
developers and developers coming from a different language to learn PHP
and also required the developer to learn the language details by heart
instead of being able to rely on their intuition.
I'm already leaning towards "Don't want static classes", but if they use
an attribute instead of a keyword, then it's going to be a clear "no".
See also my email in response to Ayesh.
Best regards
Tim Düsterhus
PS: Can you please cut the quoted parts to a minimum instead of
including the original email in full? That makes it much clearer to see
what part you are actually replying to and reduces the amount of storage
requiring for all the thousands of ML subscribers :-)
Hi Tim,
and I'd rather have the feature with slightly odd syntax rather than
not at all.Absolutely not. PHP is already odd enough as it is. We should not add
additional oddness in the interest of pushing a new screw-shaped
feature in with a sledgehammer. Any additional oddity makes it harder
for Junior developers and developers coming from a different language
to learn PHP and also required the developer to learn the language
details by heart instead of being able to rely on their intuition.
Don't worry, I couldn't bring myself to seriously entertain using an
attribute instead of a keyword. I'll update the RFC to include it as a
rejected feature.
I'm already leaning towards "Don't want static classes"
Why? It is important to understand what your misgiving are in case there
anything we can do to assuage them.
Cheers,
Bilge
Hi
I'm already leaning towards "Don't want static classes"
Why? It is important to understand what your misgiving are in case there
anything we can do to assuage them.
I don't see value in being able to explicitly mark a class as static
for the reasons that have already been brought forward by other
participants (such as Larry).
But more importantly, the RFC and discussion so far don't really
convince me that any of the participants in favor of static classes
really know what they want and thought about all the implications of that.
I strongly favor an opinionated RFC where the RFC author did their
research and makes it clear why the proposal is the right choice and
backs this up by proper arguments. Of course this doesn't mean that the
RFC author should not listen to the list discussion, but the high level
details should be clear right from the beginning. As of now the RFC
still has some open questions regarding "core functionality" and even
intents to leave them as a secondary vote.
In other words, too many cooks spoil the broth.
Given the upcoming feature freeze, the current list volume and core
folks being busy with finishing up and polishing their own RFCs for PHP
8.4, the timing doesn't really help getting the necessary attention
towards your RFC either. I might be more receptive towards a quieter
period of the year, where I can take the time to really think about the
RFC, like I do for other RFCs as well. My earlier responses towards the
Lazy Objects RFC might be a good example towards the level of detail I
try to give RFCs. Even when I don't personally understand them or don't
see myself using them (yet), I want a best-possible result that will not
cause sadness 3 years down the road.
Best regards
Tim Düsterhus
I strongly favor an opinionated RFC where the RFC author did their research and makes it clear why the proposal is the right choice and backs this up by proper arguments. Of course this doesn't mean that the RFC author should not listen to the list discussion, but the high level details should be clear right from the beginning. As of now the RFC still has some open questions regarding "core functionality" and even intents to leave them as a secondary vote.
With respect, I completely support your right to choose what you favor.
However, I would like to suggest there might be some negative consequences to your approach and request that you reconsider your what you favor.
Yes, if an RFC author does their research and makes it clear why the proposal is the right choice and backs this up by proper arguments then it makes for a better RFC which can more easily be reviewed.
OTOH, it limits the pool of RFC authors who can successfully achieve that bar to only those who know what research needs to be done and which arguments resonate well resonate with list members. Effectively it limits the successful pool of RFC authors to the list of prior successful RFC authors who — through experience — have developed enough knowledge about what research needs to be done and which arguments resonate well with list members.
Yes someone can overcome these experience barriers by submitting numerous RFCs that fail and over years of time eventually gain enough knowledge and experience to succeed, but realistically how many people will go through that gauntlet?
The problem with the approach is there over time there becomes is a diminishing number of individuals who can and will submit RFCs, and the language slowly dies:
https://thenewstack.io/why-php-usage-has-declined-by-40-in-just-over-2-years/
Currently the culture of this list is people submit an RFC and if they can endure the crucible to come out the other side their RFC may be adopted. But few can endure that crucible. Further, brainstorming on the list — as recent evidence has shown — is effectively impossible.
The experienced RFC submitters know to go off list and work with other experienced RFC submitters to prepare an RFC prior to having to endure an onslaught of criticism from this list. The problem for new RFC writers is they don't know who to ask nor have the clout to approach people to get such collaborators.
IMO it would be better if the culture here approached would-be RFC writers differently. I instead experienced RFC writers provided a bit of mentoring to new RFC writers, encourage them to cultivate their ideas in a version-controlled repo off this list, but also have the mentor call for list members to collaborate with the would-be RFC writer in a discussion forum on their repo. Once those collaborators feel the RFC is fully-baked then they could present to the list.
If that culture existed, your strongly favored well-researched and clearly-argued RFC could be the norm rather than the exception.
Food for thought?
-Mike
P.S. I currently have a repo for an RFC where I want to make a call for collaboration, but I do not know how to call for help on the list without attracting those who would immediately swarm the discussion forum to flood the channel with criticism before the ideas are even fully baked.
I strongly favor an opinionated RFC where the RFC author did their
research and makes it clear why the proposal is the right choice and
backs this up by proper arguments. Of course this doesn't mean that
the RFC author should not listen to the list discussion, but the high
level details should be clear right from the beginning. As of now the
RFC still has some open questions regarding "core functionality" and
even intents to leave them as a secondary vote.In other words, too many cooks spoil the broth.
I won't pretend I had the knowledge and experience to tackle this alone.
I stood on the shoulders of giants to make this PR possible, and even
before PR, I didn't have a clear view when I first casually strolled
into internals. Talking to the experts here helped me find the words I
was searching for and ensure edge cases were considered. That said, I
hope you don't think me soft, this was not a design by committee; the
RFC is a product of my own work and the decisions now made are a result
of my own convictions, bolstered but not coerced by the input of others.
Moreover, now the RFC is finished at version 1.3, I am very proud of
what it has become and stand by every implementation decision made
pertaining to specific semantics; I am convinced they are correct and
would not benefit from any further modification, with the benefit of
experience writing the implementation behind me. I hope you, too, are
equally convinced if you would now humble me with another read.
Kind regards,
Bilge
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.
Just one point of feedback: for clarity I think it would be good if it
mentions that creating dynamic properties i.e. $this->dynamicProp =
'bar' would also throw at runtime (or even compile time if doable?).
As for voting intention, it sounds totally reasonable to me, and while I
don't see myself using it much I don't see a reason to be against it, so
👍🏻
Best
Jordi Boggiano
@seldaek - https://seld.be
Hi Jordi,
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.
Just one point of feedback: for clarity I think it would be good if it
mentions that creating dynamic properties i.e. $this->dynamicProp =
'bar' would also throw at runtime (or even compile time if doable?).
Absolutely. I'll include a note about this in the RFC.
As for voting intention, it sounds totally reasonable to me, and while
I don't see myself using it much I don't see a reason to be against
it, so 👍🏻
Thank you! 🙏🏻
Kind regards,
Bilge
P.S. Thanks for Composer 🙂
Hi again Jordi,
Hi Jordi,
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.
Just one point of feedback: for clarity I think it would be good if
it mentions that creating dynamic properties i.e. $this->dynamicProp
= 'bar' would also throw at runtime (or even compile time if doable?).
Absolutely. I'll include a note about this in the RFC.
On second thoughts, I don't think dynamic properties can apply at all.
The notion of $this
is a reference to an object instance; static
classes cannot be instantiated, so the concept of dynamic properties
simply cannot exist, and that's really all there is to it 😅 (unless I'm
missing something).
Cheers,
Bilge
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.
Just one point of feedback: for clarity I think it would be good if
it mentions that creating dynamic properties i.e. $this->dynamicProp
= 'bar' would also throw at runtime (or even compile time if doable?).
Absolutely. I'll include a note about this in the RFC.On second thoughts, I don't think dynamic properties can apply at all.
The notion of$this
is a reference to an object instance; static
classes cannot be instantiated, so the concept of dynamic properties
simply cannot exist, and that's really all there is to it 😅 (unless
I'm missing something).
Yeah sorry that is indeed not needed as it already works that way
https://3v4l.org/TYIiV
It is not compile time though, but that's a separate concern.
Jordi Boggiano
@seldaek - https://seld.be
Hey Bilge,
I'm not usually a resident of these discussions, but it seems like this RFC
is heading into a wrong direction. Let me explain: as it currently stands,
static properties and methods live separately from instance properties and
methods. That means a couple of limitations, namely: a static class member
can never implement an interface's contract, and hence a static class could
never be used as an instance; static class members have a separate
reflection API; static class members cannot have expression initializers;
there's no static constructor; and so on. Adding static classes
would not
solve any of the above issues, and they would still be barely useful.
To counter these issues, Kotlin has a concept of data objects
: <
https://kotlinlang.org/docs/object-declarations.html#data-objects>. They
look like regular classes, but only one instance of a data object is
created - when it's first accessed by other code. The closest alternative
in PHP would be an enum with a single case. Unlike static classes, data objects
don't have any of the problems associated with static members.
They can be passed around as an instance of a class. This allows
implementing interfaces, and replacing a data object
with a regular class
instance without having to change all member access from static to
instance. They would also be able to inherit the syntax and semantics of
regular class constructors:
object Converter {
private array $map = new Map();
public function __construct() {
$this->map['miles to km'] = 1.6;
}
public function convert(string $type, float $value): float {
return $value * $this->map[$type];
}
}
doSomeConversion(Converter::object);
// If `Converter` is ever to become a regular class, none of the related
code would require changes.
function doSomeConversion(Converter $converter) {
$result = $someUtils->convert('miles to km', 123);
}
That would be functionally equivalent to:
class Converter {
private static self $instance;
public static function instance(): self {
return self::$instance ??= new self();
}
public function convert(float $something): float {}
}
doSomeConversion(Converter::instance());
Of course, this is already possible, as shown in the second example. But so
is this RFC. Implementing data objects would actually bring them on-par
with regular classes, and likely cause less drama overall.
Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.This work is based on the previous discussion thread on this list of the
same name, and hopefully captured all the relevant details,
notwithstanding anything unanticipated that may present itself during
the implementation. Let me know if you feel anything important has been
missed. I am aware it omits to mention specifics about messages so
emitted when runtime or compile-time errors occur, but I anticipate this
can be hashed out in the PR, unless consensus indicates otherwise.I am aware this idea is not supported by everyone, but there seemed to
be enough positive voices for it to be worth a shot. I'd like to get a
better idea of where people might stand when it comes down to a vote,
now there is a formal RFC, so we know whether it's worth completing the
implementation, although any sentiments so proffered are of course not a
commitment to vote any particular way and nobody should feel compelled
to speak to that unless comfortable. Looking forward to feedback!Cheers,
Bilge
Hey Bilge,
I'm not usually a resident of these discussions, but it seems like
this RFC is heading into a wrong direction. Let me explain: as it
currently stands, static properties and methods live separately from
instance properties and methods. That means a couple of limitations,
namely: a static class member can never implement an interface's
contract, and hence a static class could never be used as an instance;
static class members have a separate reflection API; static class
members cannot have expression initializers; there's no static
constructor; and so on. Addingstatic classes
would not solve any of
the above issues, and they would still be barely useful.To counter these issues, Kotlin has a concept of
data objects
:
https://kotlinlang.org/docs/object-declarations.html#data-objects.
Hi Alex,
If you wish to implement data objects, what part of the current proposal
precludes you from doing so?
Cheers,
Bilge
Hi Alex,
If you wish to implement data objects, what part of the current proposal
precludes you from doing so?
None, but they both try to solve the same problem, so it's highly unlikely
that data objects would ever be considered if this RFC is accepted. And
while static classes fit better with lots of existing PHP code, data
classes (or a similar proposal) would bring more benefit to the table in
the long run, which is why I was hoping for an alternative solution to be
considered and/or discussed. I'm not planning to pursue the data objects
proposal further, but it was still worth mentioning so the internals are
aware of the alternatives to this RFC.
a static class member can never implement an interface's contract
Well, PHP is a weird one here compared to other languages
Interfaces can contain contracts for static methods and they are checked
just like usual non-static methods.
Example: https://3v4l.org/8cuXW
With late static binding, you can define static abstract methods and
basically do code reuse through inheritance.
Example: https://3v4l.org/pid7W
I'm not saying I would ever use such a thing, just that they exist and
others might find them useful so why build limits around it?
A limit is just extra code to maintain and make sure you use it
consistently.
I believe that a static class should have the principle of no allowed
instance and only static methods, without any impact on inheritance:
- There can be a static interface and a static abstract class
- A static class can extend a non-static class, or implement an interface
or abstract class as long as it does not require to implement a non-static
method. - A static class can be extended only by another static class
- As static interface can be extended only by a static class
Basically, when a static class gets into the inheritance chain, all the
extending classes will be static and there is a guarantee that there will
never be an instance of that class.
Making sure a static class does just that, limiting the methods and
properties in it to only be static, will keep things simpler going forward
when thinking about interactions with other features.
Like readonly static class would not work right now, but it will work if
readonly will be implemented for static properties, and that should be
doable effortless.
Alex
Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.This work is based on the previous discussion thread on this list of the
same name, and hopefully captured all the relevant details,
notwithstanding anything unanticipated that may present itself during
the implementation. Let me know if you feel anything important has been
missed. I am aware it omits to mention specifics about messages so
emitted when runtime or compile-time errors occur, but I anticipate this
can be hashed out in the PR, unless consensus indicates otherwise.I am aware this idea is not supported by everyone, but there seemed to
be enough positive voices for it to be worth a shot. I'd like to get a
better idea of where people might stand when it comes down to a vote,
now there is a formal RFC, so we know whether it's worth completing the
implementation, although any sentiments so proffered are of course not a
commitment to vote any particular way and nobody should feel compelled
to speak to that unless comfortable. Looking forward to feedback!
while i wouldn't ordinarily find a lot of use-cases for myself for this, i
think its consistent with final and readonly to allow static on classes as
well. The code I believe would be mostly at compile time anyways to do
these checks, except for new $class.
So in general I would vote yes for this, if all edge cases are clear and
considered.
Cheers,
Bilge
Hi Internals!
I am excited to announce the final implementation for Static Class is
ready for review at https://github.com/php/php-src/pull/14861 and
includes a brief summary of the key semantics of the feature.
Furthermore, the 1.3 (presumed) final version of the RFC is now
published at https://wiki.php.net/rfc/static_class.
Naturally, if there are any further weighty comments or criticisms to be
levied against either one of these, they may still be subject to changes
as appropriate.
Tomorrow the minimum period elapses before the vote may be started.
Discussions on this topic have been quiet for about a week as well, so
if there are no major concerns outstanding, I expect to announce the
vote to start very soon.
Kind regards,
Bilge
Hi Internals!
I am excited to announce the final implementation for Static Class is ready for review at https://github.com/php/php-src/pull/14861 and includes a brief summary of the key semantics of the feature.Furthermore, the 1.3 (presumed) final version of the RFC is now published at https://wiki.php.net/rfc/static_class.
Congrats on getting it to this point.
I support this in all but the RFC's restriction on abstract
, as I have previously mentioned on the list.
-Mike
Naturally, if there are any further weighty comments or criticisms to be levied against either one of these, they may still be subject to changes as appropriate.
Tomorrow the minimum period elapses before the vote may be started. Discussions on this topic have been quiet for about a week as well, so if there are no major concerns outstanding, I expect to announce the vote to start very soon.
Kind regards,
Bilge
Congrats on getting it to this point.
Thanks. It's been an adventure :^)
I support this in all but the RFC's restriction on `abstract`, as I have previously mentioned on the list.
I must have missed a key point here. Let's suppose we're writing a
follow-up RFC to permit static
and abstract
together. In as few
sentences as possible, what is the benefit conferred to the developer?
Cheers,
Bilge
Congrats on getting it to this point.
Thanks. It's been an adventure :^)I support this in all but the RFC's restriction on
abstract
, as I have previously mentioned on the list.
I must have missed a key point here. Let's suppose we're writing a follow-up RFC to permitstatic
andabstract
together. In as few sentences as possible, what is the benefit conferred to the developer?Cheers,
Bilge
Hi,
I'm sure Mike has his own answer for this, but I'm going to reiterate mine again, because it apparently wasn't really understood the first several times I said it:
The reasons are two fold:
(a) so that a static class can declare abstract methods either explicitly or implicitly (by implementing an interface without providing concrete implementations of all methods in the interface)
(b) to keep consistency with regular classes.
The suggested static keyword for classes doesn't introduce any additional behaviour that isn't already possible, it just prevents some uses without the need for boilerplate - the main purpose is to "signify developer intent".
The actual behaviour applied to "static" classes is already possible in PHP by simply omitting any instance members and declaring a private constructor. These classes work fine with the abstract keyword. There are no ambiguities, no gotchas or foot guns, there is nothing confusing. It's a standard part of class hierarchy.
So really the question should be: why do you feel the need to disallow a combination that has no technical issues, and works already? If you're going to disallow abstract why not disallow any class inheritance at all? Because that's what abstract relates to: class hierarchy. Why remove some support but keep the rest?
Cheers
Stephen
On Mon, Jul 8, 2024 at 1:12 PM Stephen Reay php-lists@koalephant.com
wrote:
So really the question should be: why do you feel the need to disallow a
combination that has no technical issues, and works already? If you're
going to disallow abstract why not disallow any class inheritance at all?
Because that's what abstract relates to: class hierarchy. Why remove some
support but keep the rest?
Exactly what I wanted to say for this topic. Have a look at this example
that could be very similar in production code in some systems:
<?php
interface A {
public static function run();
public static function stop();
}
abstract class B implements A {
public static function run() {
static::create();
static::start();
}
}
class C extends B {
public static function create() {
echo "Create\n";
}
public static function start() {
echo "Start\n";
}
public static function stop() {
echo "Stop\n";
}
}
function execute($class) {
if (!is_subclass_of($class, A::class)) {
throw new RuntimeException("Class must implement A interface");
}
$class::run();
$class::stop();
};
execute(C::class);
If we support inheritance for static classes, we should allow static on
both interface and abstract classes.
Alex
On Mon, Jul 8, 2024 at 1:12 PM Stephen Reay php-lists@koalephant.com
wrote:So really the question should be: why do you feel the need to *disallow* a combination that has no technical issues, and works already? If you're going to disallow abstract why not disallow any class inheritance at all? Because that's what abstract relates to: class hierarchy. Why remove some support but keep the rest?
The reason to remove abstract was because it was thought static
means
the same as abstract
. That is, neither can be instantiated. However,
clearly that is short-sighted as Alex's example proves. That is, we
cannot simply replace abstract
with static
because that precludes us
from having an incomplete definition where some methods are still not
yet implemented. As such, I am quite convinced by your arguments, and
will make the change to add abstract
support back in; mainly because
removing abstract support defies our fundamental razor (it's something
we can already do).
If we support inheritance for static classes, we should allow static
on both interface and abstract classes.
What do you mean by /allow static on [...] interface/? Are you saying
you also expect to see static interface
support? (This is something I
am absolutely not considering at this time, without a very good argument
in favour of).
Cheers,
Bilge
If we support inheritance for static classes, we should allow static on
both interface and abstract classes.What do you mean by allow static on [...] interface? Are you saying you
also expect to seestatic interface
support? (This is something I am
absolutely not considering at this time, without a very good argument in
favour of).For completeness, if we think that the static keyword on a class-level
entity means that it will allow only static members on that entity, all
class-level entities should be able to be marked as "static".:
Yes, it might not be really required, but I can see how it would help
define a static interface that can only be implemented by a static class.
Reading on :
A static class only permits extending a parent class that is also marked
static. A non-static class cannot extend a static class.
The wording is a bit confusing for me.
But I understand that once a class is static, all the chain of inheritance
should be made of static classes, going up or down (and I would also think
we can add interfaces and traits.).
If interfaces are not included, do we allow implementing an interface? If
we allow implementing an interface, should that interface contain only
static members? Same for traits.
Alex
But I understand that once a class is static, all the chain of
inheritance should be made of static classes, going up or down (and I
would also think we can add interfaces and traits.).
Correct.
If interfaces are not included, do we allow implementing an interface?
Yes.
If we allow implementing an interface, should that interface contain
only static members?
Yes. You can technically implement an interface that has instance
methods, but you will either: get a compile-time error that you didn't
implement the instance method, or a compile-time error that you didn't
mark the (instance) method as static in a static class. So although you
won't get an error about implementing the interface itself, you will be
forced to not implement an interface containing any instance methods in
a static class, by one of those two (somewhat indirect) errors.
Same for traits.
Yes
For completeness, if we think that the static keyword on a class-level
entity means that it will allow only static members on that entity,
all class-level entities should be able to be marked as "static".:
I understand that sentiment, however I'm still not going to entertain it
right now because this RFC seems to have a tenuous chance of passing at
best. I should think we will be lucky to get 50% of the vote, let alone
the 66% required to pass, and any further (unnecessary) language
changes, such as introducing static interface
or static trait
s will
probably lower those odds. I'm sorry it's like that, but that's how the
landscape looks to me. But not to be too disheartened; both of those
things can be trivially added in a follow-up PR if there is a strong
desire. That is, accepting this RFC in no way precludes the possibility
of going down that road later.
Cheers,
Bilge
Hi Internals!
I am excited to announce the final implementation for Static Class is
ready for review at https://github.com/php/php-src/pull/14861 and
includes a brief summary of the key semantics of the feature.Furthermore, the 1.3 (presumed) final version of the RFC is now
published at https://wiki.php.net/rfc/static_class.Naturally, if there are any further weighty comments or criticisms to
be levied against either one of these, they may still be subject to
changes as appropriate.
For those of you (not) following along at home, a quick update:
After consulting with my Design Council (not a design by committee BTW),
we agreed to release the restriction on abstract static
. The RFC has
been updated to 1.4 and the PR has been updated in kind to allow
abstract static classes, since abstract static methods are already
present in PHP and to forbid them in the context of static classes would
be to forgo our fundamental design razor.
I expect to announce the vote to start very soon.
In light of this last-minute change, voting will be postponed until at
least next week, to give everyone some time to catch up.
Kind regards,
Bilge
Hi Internals!
I am pleased to present my first RFC: Static class
https://wiki.php.net/rfc/static_class.
Gentle reminder that voting is scheduled to start Monday, barring any
unexpected developments over this weekend.
The RFC is unchanged since including support for abstract static
last
week, other than the addition of a /discussion/ section, to capture some
of the criticisms levied against the proposal, and /in the wild/ section
to explore the prevalence of implicit static classes in open source that
might benefit from the proposal.
Cheers,
Bilge