Re: [RFC] [Discussion] Add get_declared_enums() function

From: Date: Sun, 06 Oct 2024 18:50:46 +0000
Subject: Re: [RFC] [Discussion] Add get_declared_enums() function
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to internals+get-125759@lists.php.net to get a copy of this message
> On Oct 6, 2024, at 3:25 AM, Juliette Reinders Folmer <php-internals_nospam@adviesenzo.nl> > wrote: > > On 4-10-2024 13:44, Nicolas Grekas wrote: > > 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 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. > > 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). 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.)

« previous php.internals (#125759) next »