L.S.,
After the earlier discussion [1] regarding this topic in August, it is
our pleasure to present the RFC to add a get_declared_enums()
function
to PHP for discussion.
https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
Smile,
Ayesh and Juliette
On Wed, Oct 2, 2024 at 1:48 AM Juliette Reinders Folmer <
php-internals_nospam@adviesenzo.nl> wrote:
L.S.,
After the earlier discussion [1] regarding this topic in August, it is our
pleasure to present the RFC to add aget_declared_enums()
function to PHP
for discussion.https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
I'm all for get_declared_enums()
.
However, I don't accept that enums are not classes and going with the
assumption that they are not will bring more problems than it solves.
I noticed how you analyzed things internally, that everything is a class
internally, including an interface or a trait.
But this is an API for the userland, and in userland this is not true.
The 3 structures: classes, interfaces and traits and distinct things that
you can use in different ways in (generated) code.
I believe that in userland, the common understanding is that enums are just
a specific type of class, final ones.
I would find it surprising if get_declared_classes()
would not return
enums.
Avoiding a BC break would be nice also if there is no reason for it.
One would be able to get only the enums by using something like:
function get_declared_enums_only() {
return array_diff(get_declared_classes(), get_declared_enums());
}
--
Alex
L.S.,
After the earlier discussion [1] regarding this topic in August, it is our pleasure to present the RFC to add a
get_declared_enums()
function to PHP for discussion.https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
I'm all for
get_declared_enums()
.
However, I don't accept that enums are not classes and going with the assumption that they are not will bring more problems than it solves.I noticed how you analyzed things internally, that everything is a class internally, including an interface or a trait.
But this is an API for the userland, and in userland this is not true.
The 3 structures: classes, interfaces and traits and distinct things that you can use in different ways in (generated) code.I believe that in userland, the common understanding is that enums are just a specific type of class, final ones.
I would find it surprising ifget_declared_classes()
would not return enums.Avoiding a BC break would be nice also if there is no reason for it.
One would be able to get only the enums by using something like:function get_declared_enums_only() { return array_diff(get_declared_classes(), get_declared_enums()); }
--
Alex
Interesting observation Alexandru,
I find it weird that class_exists("MyEnum") would return true, but there is only one symbol table—you can’t name a class and enum with the same name, so it makes some sense. However, while enums have “some” similarities with classes in PHP, they are not the same. For example, you cannot implement arbitrary interfaces (ie, Stringable), you cannot extend another class, you cannot instantiate them with “new”, you cannot have state, you cannot clone them, magic methods are forbidden, etc.
You cannot build a “class” with these rules in PHP, so I don’t think enums quack sufficiently like classes to be called a class. I would argue that it is an object, however. I think it would be worth implementing a get_declared_objects() that behaves like get_declared_classes()
currently does.
— Rob
You cannot build a “class” with these rules in PHP, so I don’t think enums quack sufficiently like classes to be called a class. I would argue that it is an object, however. I think it would be worth implementing a get_declared_objects() that behaves like
get_declared_classes()
currently does.
Objects are instantiated classes, and not declared elements, so that name wouldn't make sense.
cheers
Derick
On Wed, Oct 2, 2024 at 1:48 AM Juliette Reinders Folmer <
php-internals_nospam@adviesenzo.nl> wrote:L.S.,
After the earlier discussion [1] regarding this topic in August, it is our
pleasure to present the RFC to add aget_declared_enums()
function to PHP
for discussion.https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
I'm all for
get_declared_enums()
.
However, I don't accept that enums are not classes and going with the
assumption that they are not will bring more problems than it solves.I noticed how you analyzed things internally, that everything is a class
internally, including an interface or a trait.
But this is an API for the userland, and in userland this is not true.
The 3 structures: classes, interfaces and traits and distinct things that
you can use in different ways in (generated) code.I believe that in userland, the common understanding is that enums are
just a specific type of class, final ones.
I would find it surprising ifget_declared_classes()
would not return
enums.Avoiding a BC break would be nice also if there is no reason for it.
One would be able to get only the enums by using something like:function get_declared_enums_only() { return array_diff(get_declared_classes(), get_declared_enums()); }
--
AlexInteresting observation Alexandru,
I find it weird that class_exists("MyEnum") would return true, but there
is only one symbol table—you can’t name a class and enum with the same
name, so it makes some sense. However, while enums have “some” similarities
with classes in PHP, they are not the same. For example, you cannot
implement arbitrary interfaces (ie, Stringable), you cannot extend another
class, you cannot instantiate them with “new”, you cannot have state, you
cannot clone them, magic methods are forbidden, etc.You cannot build a “class” with these rules in PHP, so I don’t think enums
quack sufficiently like classes to be called a class. I would argue that it
is an object, however. I think it would be worth implementing a
get_declared_objects() that behaves likeget_declared_classes()
currently
does.— Rob
Yes, that's a good point as well.
I think my view comes from when I initially dug (15+ years ago) into what
an enum in Java is, and learned that it is just a syntactic sugar, and a
final class would be generated implementing Comparable
and extending an
abstract class Enum
.
And I think in PHP that could be a similar view. And most of the
limitations we have are not impossible to create with a standard class.
I think in time we might get to remove some limitations.
I, personally, don't agree with the Stringable
related limitation.
And also with the limitation on no state. In Java this is the simple way to
create a singleton: an enum with one case; and we can't have this in PHP.
If we remove the limitations, should we reclassify at that point enums as
classes?
--
Alex
I think my view comes from when I initially dug (15+ years ago) into
what an enum in Java is, and learned that it is just a syntactic sugar,
and a final class would be generated implementingComparable
and
extending an abstract classEnum
.And I think in PHP that could be a similar view. And most of the
limitations we have are not impossible to create with a standard class.
That is roughly the way enums are implemented in several languages, including PHP.
I think in time we might get to remove some limitations.
I, personally, don't agree with theStringable
related limitation.
This has been discussed numerous times already. Please don't bring it up here, it's not relevant to this thread.
And also with the limitation on no state. In Java this is the simple
way to create a singleton: an enum with one case; and we can't have
this in PHP.
That is what we mean by ADTs or Tagged Unions (various names for the same thing), and it's something Ilija and I have on the roadmap. It's been on the roadmap since the first enum release, but we deliberately punted it for later to keep the initial RFC manageable. It's also dependent on the pattern matching RFC, which hopefully we'll be able to bring up for discussion for 8.5.
If we remove the limitations, should we reclassify at that point enums
as classes?
Enums already are classes. I don't know what reclassification you're talking about. The RFC is about adding a "get me a list of only those classes that are enums" function to PHP. Changing how Enums behave or are implemented is wildly out of scope.
--Larry Garfield
If we remove the limitations, should we reclassify at that point enums
as classes?Enums already are classes. I don't know what reclassification you're
talking about. The RFC is about adding a "get me a list of only those
classes that are enums" function to PHP. Changing how Enums behave or are
implemented is wildly out of scope.
Sorry if my reply wasn't clear enough and somehow ambiguous.
I agree. Enums are classes. And my reply was just a way to explain this
view in a friendly manner.
Maybe reading previous replies in the thread could be more clear on my
stance.
Comming back to the RFC, I think it needs to be changed as I believe it
focuses too much on internals, ignoring userland view.
Just adding the new function should be enough.
-- Alex
__
L.S.,
After the earlier discussion [1] regarding this topic in August, it is our pleasure to present the RFC to add a
get_declared_enums()
function to PHP for discussion.https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
I'm all for
get_declared_enums()
.
However, I don't accept that enums are not classes and going with the assumption that they are not will bring more problems than it solves.I noticed how you analyzed things internally, that everything is a class internally, including an interface or a trait.
But this is an API for the userland, and in userland this is not true.
The 3 structures: classes, interfaces and traits and distinct things that you can use in different ways in (generated) code.I believe that in userland, the common understanding is that enums are just a specific type of class, final ones.
I would find it surprising ifget_declared_classes()
would not return enums.Avoiding a BC break would be nice also if there is no reason for it.
One would be able to get only the enums by using something like:function get_declared_enums_only() { return array_diff(get_declared_classes(), get_declared_enums()); }
--
AlexInteresting observation Alexandru,
I find it weird that class_exists("MyEnum") would return true, but there is only one symbol table—you can’t name a class and enum with the same name, so it makes some sense. However, while enums have “some” similarities with classes in PHP, they are not the same. For example, you cannot implement arbitrary interfaces (ie, Stringable), you cannot extend another class, you cannot instantiate them with “new”, you cannot have state, you cannot clone them, magic methods are forbidden, etc.
You cannot build a “class” with these rules in PHP, so I don’t think enums quack sufficiently like classes to be called a class. I would argue that it is an object, however. I think it would be worth implementing a get_declared_objects() that behaves like
get_declared_classes()
currently does.— Rob
Yes, that's a good point as well.
I think my view comes from when I initially dug (15+ years ago) into what an enum in Java is, and learned that it is just a syntactic sugar, and a final class would be generated implementing
Comparable
and extending an abstract classEnum
.And I think in PHP that could be a similar view. And most of the limitations we have are not impossible to create with a standard class.
I think in time we might get to remove some limitations.
I, personally, don't agree with theStringable
related limitation.
And also with the limitation on no state. In Java this is the simple way to create a singleton: an enum with one case; and we can't have this in PHP.If we remove the limitations, should we reclassify at that point enums as classes?
--
Alex
Hey Alex,
IMHO, the only thing keeping an enum from being "sugared classes" is the ability to define state. I'm not even sure why it is a limitation because it is relatively easy to "hack it in": https://3v4l.org/nqZfK
Being able to define state and behavior are fundamental parts of what makes a class a class. If you can't have state, then I'm not sure it is a class. We're getting into theoretical computer science here, but that is, I think, a generally accepted basic definition in Object Oriented Programming.[1]
The rest could be explained as just sugar for:
- final class
- extend base enum class (hence why it can't extend another class)
- final clone method in base class which prevents cloning
- hidden magic method implementations that throw (hence unable to implement stringable)
- singletons for each case
- etc
(and before someone argues that it "isn't how it works", I am merely describing the sugar)
So, yes, once that restriction is lifted, I think we could officially call them classes. Until then though, I think they're just "enums?"
You cannot build a “class” with these rules in PHP, so I don’t think enums quack sufficiently like classes to be called a class. I would argue that it is an object, however. I think it would be worth implementing a get_declared_objects() that behaves like
get_declared_classes()
currently does.Objects are instantiated classes, and not declared elements, so that name wouldn't make sense.
cheers
Derick
This is also why I suggested calling them objects instead of classes. Enum cases are instantiated enums which are objects, but they aren't classes. We could be more specific and call it get_declared_object_types()
I'd absolutely love to hear a reason, rooted in computer science, why PHP enums are classes. I'm no expert on the subject, but this has bothered me for years... so I would love to learn more or discuss the topic further.
[1]: https://books.google.com/books?id=9NGWq3K1RwUC&pg=PA18 Foundations of Object Oriented Languages: types and semantics, Bruce, 2002 -- just had to break out an old text book :)
— Rob
On Wed, Oct 2, 2024 at 10:20 AM Alexandru Pătrănescu drealecs@gmail.com
wrote:
One would be able to get only the enums by using something like:
function get_declared_enums_only() { return array_diff(get_declared_classes(), get_declared_enums()); }
Sorry, I somehow got confused, and I meant to say "to get only the class
that are not enums" and it would be like this:
function get_declared_class_without_enum() {
return array_diff(get_declared_classes(), get_declared_enums());
}
-- Alex
L.S.,
After the earlier discussion [1] regarding this topic in August, it is our pleasure to present the RFC to add a
get_declared_enums()
function to PHP for discussion.https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
Smile,
Ayesh and Juliette
The RFC, and its course of action, makes total sense to me.
As a counterpoint to the argument presented on the list that Enums should still be returned by get_declared_list() because they are "classes":
Interfaces and traits are also "classes" internally, and yet they are not returned.
We make a distinction in userland, and this should be followed by the provided functions.
Best regards,
Gina P. Banyard
Hi
Am 2024-10-03 14:01, schrieb Gina P. Banyard:
As a counterpoint to the argument presented on the list that Enums
should still be returned by get_declared_list() because they are
"classes":
Interfaces and traits are also "classes" internally, and yet they are
not returned.
We make a distinction in userland, and this should be followed by the
provided functions.
From my userland developer mental model PoV enum
s are just special
classes. Leaving aside Reflection or other introspection functionality
and enum object behaves just like a "regular" class object. The same is
not true for interfaces and traits, which are structures that help you
build a class (including enum classes, which support both interfaces and
traits).
Best regards
Tim Düsterhus
L.S.,
After the earlier discussion [1] regarding this topic in August, it is our
pleasure to present the RFC to add aget_declared_enums()
function to PHP
for discussion.https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
My only comment is that I don't think you should have three different
votes, but just the single one for the whole proposal.
cheers,
Derick
Hi Juliette,
L.S.,
After the earlier discussion [1] regarding this topic in August, it is our
pleasure to present the RFC to add aget_declared_enums()
function to PHP
for discussion.https://wiki.php.net/rfc/get_declared_enums
We look forward to your feedback and hope for a constructive discussion.
Introduction of the new function: get_declared_enums()
About this proposal, I shared a one-liner in the previous thread that shows
listing only enums is trivial already.
IMHO we don't need this function since the engine already provides
everything one needs if they want to list enums. I won't object either, I'm
just "-0".
Deprecation of using class_exists()
on enum names
This is a big NO on my side. This will break perfectly fine code for the
sake of some high level ideas that matter less is practice than ensuring
stability of the PHP platform. A BC break has to be worth it and this is
clearly not the case to me. The canonical examples are checks like
class_exists($c) || interface_exists($c, false) || trait_exists($c, false)
. This is common code to check if a symbol exists in current PHP.
Yet, with your RFC, all such checks would become broken immediately.
BTW, this makes me wonder if we could have a new symbol_exists() function,
that'd basically do the above checks in one go? Mixing this idea with
Claude's, the signature could be symbol_exists($class, $filter = -1,
$autoload = true), where $filter is a bitfield that'd allow listing only
classes, abstract classes, interfaces, enums, traits at will?
Change of the return value of get_declared_classes()
This proposal is problematic on two aspects:
- The planned BC break feels needless to me. Its motivation is very
moot compared to its impact on the PHP community, which will be forced to
update perfectly fine code. - The BC break is planned without any ahead-of-change deprecation
notice (except doc of course). From a deprecation policy POV, we reject
this practice in the Symfony community. We don't do "hard BC breaks", or
"unannounced" ones: we mandate that any BC break is first announced in the
current major. This ensures the community won't miss the notice, and won't
discover the BC break when it's very late and thus costly. There is always
a way to follow that policy, so I'd strongly recommend adopting this
practice in PHP itself, and in this RFC today. Here, this could be done by
either keeping the function as is in PHP 9, or just deprecating it (in
favor of get_declared_symbols()?)
You've been a rightfully vocal criticizer of BC breaks / deprecations in
PHP. Please help the vast part of the community that favors stability 🙏
Nicolas
Hi
Am 2024-10-04 13:44, schrieb Nicolas Grekas:
Introduction of the new function: get_declared_enums()
About this proposal, I shared a one-liner in the previous thread that
shows
listing only enums is trivial already.
IMHO we don't need this function since the engine already provides
everything one needs if they want to list enums. I won't object either,
I'm
just "-0".
Agreed.
Deprecation of using
class_exists()
on enum namesThis is a big NO on my side. This will break perfectly fine code for
the
sake of some high level ideas that matter less is practice than
ensuring
stability of the PHP platform. A BC break has to be worth it and this
is
clearly not the case to me. The canonical examples are checks like
class_exists($c) || interface_exists($c, false) || trait_exists($c, false)
. This is common code to check if a symbol exists in current
PHP.
Yet, with your RFC, all such checks would become broken immediately.
Also agreed here. I don't think that the RFC lists particularly strong
arguments in favor of the breaking change. From what I see the main
argument is perceived consistency. But as can be seen in this
discussion, it's possible to make the argument of consistency in both
directions.
I also believe that consistency is a strong argument to make before a
feature is introduced to not make PHP any more inconsistent, but once
the "damage is done", making behavioral changes would just make the
damage larger. I'm specifically highlighting behavioral here.
Deprecating something and then later removing it will very visibly break
the code if one ignores the deprecation notice, but when making a
behavioral change, code will instead silently misbehave. As Nicolas also
mentioned this is especially true for the change to
get_declared_classes()
which would be unable to emit the deprecation
notice at all!
Best regards
Tim Düsterhus
Hi Nicolas,
Introduction of the new function: get_declared_enums()
About this proposal, I shared a one-liner in the previous thread that
shows listing only enums is trivial already.
IMHO we don't need this function since the engine already provides
everything one needs if they want to list enums. I won't object
either, I'm just "-0".
The upside of a PHP native function would be one of performance.
Deprecation of using
class_exists()
on enum namesThis is a big NO on my side. This will break perfectly fine code for
the sake of some high level ideas that matter less is practice than
ensuring stability of the PHP platform. A BC break has to be worth it
and this is clearly not the case to me. The canonical examples are
checks likeclass_exists($c) || interface_exists($c, false) || trait_exists($c, false)
. This is common code to check if a symbol
exists in current PHP. Yet, with your RFC, all such checks would
become broken immediately.
Well, this statement made me curious to see just how common this type
of code is, so I've done a scan of the Packagist top 2000 projects [1].
The check you mention is used a total of 36 times in ~20 packages out of
2000 (includes some duplication, mostly within Symfony, which also
contains the fast majority of the uses of the above mentioned combination).
The full break down of the scan results [2] are as follows:
Combination of the following function calls within a set of parentheses
(typically: control structure condition):
4 out of 4: class_exists()
+ interface_exists()
+ trait_exists()
+
enum_exists() 3
3 out of 4: class_exists()
+ interface_exists()
+
trait_exists()
36
2 out of 4: class_exists()
+
interface_exists()
131
2 out of 4: class_exists()
+
trait_exists()
8
2 out of 4: class_exists()
+
enum_exists() 1
2 out of 4: interface_exists()
+
trait_exists()
1
Combination of the following function calls within the same function
scope (not necessarily in the same statement, excluding the above):
4 out of 4: class_exists()
+ interface_exists()
+ trait_exists()
+
enum_exists() 2
3 out of 4: class_exists()
+ interface_exists()
+
trait_exists()
17
3 out of 4: class_exists()
+ interface_exists()
+
enum_exists() 3
2 out of 4: class_exists()
+
interface_exists()
32
2 out of 4: class_exists()
+
enum_exists() 4
2 out of 4: class_exists()
+
trait_exists()
2
Please note that not all of this code would need updating.
BTW, this makes me wonder if we could have a new symbol_exists()
function, that'd basically do the above checks in one go? Mixing this
idea with Claude's, the signature could be symbol_exists($class,
$filter = -1, $autoload = true), where $filter is a bitfield that'd
allow listing only classes, abstract classes, interfaces, enums,
traits at will?Change of the return value of
get_declared_classes()
This proposal is problematic on two aspects:
- The planned BC break feels needless to me. Its motivation is very
moot compared to its impact on the PHP community, which will be
forced to update perfectly fine code.
Again, let's look at the real world impact based on a scan of the
Packagist top 2000.
In the top 2000 packages, there are only 47 calls to the
get_declared_classes()
function. These calls are found in 29 packages.
[1][3]
And for the record, there are only 16 calls each to
get_declared_interfaces()
and get_declared_traits()
.
Also note that not all of this code would need updating, only that code
which is also targeting enums.
- The BC break is planned without any ahead-of-change deprecation
notice (except doc of course). From a deprecation policy POV, we
reject this practice in the Symfony community. We don't do "hard
BC breaks", or "unannounced" ones: we mandate that any BC break is
first announced in the current major. This ensures the community
won't miss the notice, and won't discover the BC break when it's
very late and thus costly. There is always a way to follow that
policy, so I'd strongly recommend adopting this practice in PHP
itself, and in this RFC today. Here, this could be done by either
keeping the function as is in PHP 9, or just deprecating it (in
favor of get_declared_symbols()?)
I hear what you are saying and largely agree with you. The problem is,
of course, that it seems unlikely that we can find a way to throw a
deprecation for this, as PHP would then also throw a deprecation for
code which needs no changes (which only intends to look at classes,
not enums).
In the RFC, we mention an alternative approach [4], building upon the
suggestion by Claude. This alternative approach would allow for
deprecations to be thrown, but would, in my estimation, need a longer
lead-time. Something like: introduce the new function in PHP 8.5,
deprecate use of the old functions in PHP 9.last and remove in PHP 10.0.
I can imagine combining the alternative approach via
get_declared_symbols() with a new symbol_exists() function like you
suggest above (with a similar slow path to deprecate and remove the old
functions).
On the plus side, the alternative approach makes for much more versatile
functionality. In a number of the cases I looked at, the results from
various get_declared_*() functions are combined before further
processing, so having a get-declared_symbols()
function would allow
for simplifying that code. The same can be said for the *_exists()
functions.
On the downside, the alternative approach makes for a larger BC break
(if combined with deprecation and eventual removal of the old functions).
Would you consider that approach preferable ?
You've been a rightfully vocal criticizer of BC breaks / deprecations
in PHP. Please help the vast part of the community that favors
stability 🙏
I evaluate each RFC on their merit and weight the impact and the effort
which would be needed to handle the deprecation (and always have). For
short: do the benefits outweigh the costs ?
There are plenty of deprecations I've stayed silent about as those (IMO)
weren't particularly problematic or even if they were, the arguments to
deprecate were particularly strong.
Just saying this, as I want to make sure people aren't confusing
"speaking up when I see a problematic change" (which I do) with "being
against deprecations" (which I'm not).
Smile,
Juliette
1: Based on the latest published release of each package and providing
the package contained source code and not just a PHAR file. Excluding
vendor and test directories. May contain some duplicates. Total number
of files scanned: 233,968.
2: Detailed results of the scan for combinations of the exists()
functions: https://gist.github.com/jrfnl/5ac6cf10e4553a5e2174cf0f58d5e305
3: Detailed results of the scan for usage of the get_declared()
functions: https://gist.github.com/jrfnl/ccb11e73d804cc5bb7fe25c6899c43d1
4:
https://wiki.php.net/rfc/get_declared_enums#were_any_alternative_approaches_considered
I can imagine combining the alternative approach via
get_declared_symbols() with a new symbol_exists() function like you
suggest above (with a similar slow path to deprecate and remove the old
functions).On the plus side, the alternative approach makes for much more
versatile functionality. In a number of the cases I looked at, the
results from various get_declared_*() functions are combined before
further processing, so having aget-declared_symbols()
function would
allow for simplifying that code. The same can be said for the
*_exists() functions.
FWIW, I'd love to have get_declared_symbols() and symbol_exists() functions, regardless of what we do with enums in particular. That's arguably a topic for another RFC, though. (And debatable if functions would count as symbols, but again, topic for another time.)
--Larry Garfield
Hi Nicolas,
Introduction of the new function: get_declared_enums()
About this proposal, I shared a one-liner in the previous thread that shows listing only enums is trivial already.
IMHO we don't need this function since the engine already provides everything one needs if they want to list enums. I won't object either, I'm just "-0".The upside of a PHP native function would be one of performance.
Deprecation of using
class_exists()
on enum namesThis is a big NO on my side. This will break perfectly fine code for the sake of some high level ideas that matter less is practice than ensuring stability of the PHP platform. A BC break has to be worth it and this is clearly not the case to me. The canonical examples are checks like
class_exists($c) || interface_exists($c, false) || trait_exists($c, false)
. This is common code to check if a symbol exists in current PHP. Yet, with your RFC, all such checks would become broken immediately.Well, this statement made me curious to see just how common this type of code is, so I've done a scan of the Packagist top 2000 projects [1].
The check you mention is used a total of 36 times in ~20 packages out of 2000 (includes some duplication, mostly within Symfony, which also contains the fast majority of the uses of the above mentioned combination).
The full break down of the scan results [2] are as follows:
Combination of the following function calls within a set of parentheses (typically: control structure condition):
4 out of 4:class_exists()
+interface_exists()
+trait_exists()
+ enum_exists() 3
3 out of 4:class_exists()
+interface_exists()
+trait_exists()
36
2 out of 4:class_exists()
+interface_exists()
131
2 out of 4:class_exists()
+trait_exists()
8
2 out of 4:class_exists()
+ enum_exists() 1
2 out of 4:interface_exists()
+trait_exists()
1Combination of the following function calls within the same function scope (not necessarily in the same statement, excluding the above):
4 out of 4:class_exists()
+interface_exists()
+trait_exists()
+ enum_exists() 2
3 out of 4:class_exists()
+interface_exists()
+trait_exists()
17
3 out of 4:class_exists()
+interface_exists()
+ enum_exists() 3
2 out of 4:class_exists()
+interface_exists()
32
2 out of 4:class_exists()
+ enum_exists() 4
2 out of 4:class_exists()
+trait_exists()
2Please note that not all of this code would need updating.
BTW, this makes me wonder if we could have a new symbol_exists() function, that'd basically do the above checks in one go? Mixing this idea with Claude's, the signature could be symbol_exists($class, $filter = -1, $autoload = true), where $filter is a bitfield that'd allow listing only classes, abstract classes, interfaces, enums, traits at will?
Change of the return value of
get_declared_classes()
This proposal is problematic on two aspects:
The planned BC break feels needless to me. Its motivation is very moot compared to its impact on the PHP community, which will be forced to update perfectly fine code.
Again, let's look at the real world impact based on a scan of the Packagist top 2000.In the top 2000 packages, there are only 47 calls to the
get_declared_classes()
function. These calls are found in 29 packages. [1][3]
And for the record, there are only 16 calls each toget_declared_interfaces()
andget_declared_traits()
.Also note that not all of this code would need updating, only that code which is also targeting enums.
The BC break is planned without any ahead-of-change deprecation notice (except doc of course). From a deprecation policy POV, we reject this practice in the Symfony community. We don't do "hard BC breaks", or "unannounced" ones: we mandate that any BC break is first announced in the current major. This ensures the community won't miss the notice, and won't discover the BC break when it's very late and thus costly. There is always a way to follow that policy, so I'd strongly recommend adopting this practice in PHP itself, and in this RFC today. Here, this could be done by either keeping the function as is in PHP 9, or just deprecating it (in favor of get_declared_symbols()?)
I hear what you are saying and largely agree with you. The problem is, of course, that it seems unlikely that we can find a way to throw a deprecation for this, as PHP would then also throw a deprecation for code which needs no changes (which only intends to look at classes, not enums).
In the RFC, we mention an alternative approach [4], building upon the suggestion by Claude. This alternative approach would allow for deprecations to be thrown, but would, in my estimation, need a longer lead-time. Something like: introduce the new function in PHP 8.5, deprecate use of the old functions in PHP 9.last and remove in PHP 10.0.
I can imagine combining the alternative approach via get_declared_symbols() with a new symbol_exists() function like you suggest above (with a similar slow path to deprecate and remove the old functions).
On the plus side, the alternative approach makes for much more versatile functionality. In a number of the cases I looked at, the results from various get_declared_*() functions are combined before further processing, so having a
get-declared_symbols()
function would allow for simplifying that code. The same can be said for the *_exists() functions.On the downside, the alternative approach makes for a larger BC break (if combined with deprecation and eventual removal of the old functions).
Given the argued downsides of the current proposal, would introducing get_declared_symbols()
+ symbols_exists()
really require deprecating the other functions?
It seems adding a get_current_enums()
and get_declared_symbols()
+ symbols_exists()
functions would address all the same userland developer needs as the proposed RFC (and more) with the only caveat being get_current_classes()
remains confusing.
To address that one remaining concern why not use add a highly visible recommendation at the top of the get_current_classes()
docs page informing people to use get_declared_symbols()
when they need only classes.
Is there a reason this approach would not be the best way forward compared to the other options currently being discussed?
-Mike
P.S. And if it is deemed critically important to get rid of the potential confusion regarding the existing get_current_classes()
behavior it could be "ultrasoft" deprecated, meaning removed in PHP 11, or just left in forever with a warning (although for the life of me I still do not understand why some people are against leaving a deprecated function in forever, especially for things that are changed for clarity, not because they cause harm by themselves.)