# Should there be a `get_declared_enums()` function ?

- Thread: https://externals.io/message/124937
- Original archive: https://news-web.php.net/php.internals/124937
- Started by Juliette Reinders Folmer on 2024-08-15T01:51:01+00:00
- Messages: 26
- RFC: Enumerations (Implemented (PHP 8.1)) — https://externals.io/rfc/enumerations.md
- RFC: Add get_declared_enums() function (Inactive) — https://externals.io/rfc/get_declared_enums.md
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/124937.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #124937 — Juliette Reinders Folmer — 2024-08-15T01:51:01+00:00

URL: https://externals.io/message/124937#124937

L.S.,

I just noticed the following, which struck me as weird/inconsistent:

There are four different OO structures in PHP:
1. Classes
2. Interfaces
3. Traits
4. Enums

For all four, an `*_exists()` function is available, i.e. 
`class_exists()`, `interface_exists()`, `trait_exists()` and 
`enum_exists()` [2].

But only for three out of the four, a `get_declared_*()` function exists.
There is `get_declared_classes()`, `get_declared_interfaces()`, 
`get_declared_traits()`, but no `get_declared_enums()` [2].

I'm aware that enums are internally considered classes and that 
`get_declared_classes()` will retrieve them [1], but the same could be 
said about interfaces and traits, yet they do have their own 
`get_declared_*()` function.

Should a `get_declared_enums()` function be added ?
And should the `get_declared_classes()` function be adjusted to exclude 
enums ?

I did check the enum RFC [3], but I couldn't find any mention or 
discussion about this in the RFC.

Smile,
Juliette


1: https://3v4l.org/0ub6I
2: https://www.php.net/manual/en/ref.classobj.php
3: https://wiki.php.net/rfc/enumerations

---

## #124941 — Larry Garfield — 2024-08-15T13:09:49+00:00

URL: https://externals.io/message/124937#124941 · In reply to: #124937

> L.S.,
>
> I just noticed the following, which struck me as weird/inconsistent:
>
> There are four different OO structures in PHP:
> 1. Classes
> 2. Interfaces
> 3. Traits
> 4. Enums
>
> For all four, an `*_exists()` function is available, i.e. 
> `class_exists()`, `interface_exists()`, `trait_exists()` and 
> `enum_exists()` [2].
>
> But only for three out of the four, a `get_declared_*()` function 
> exists.
> There is `get_declared_classes()`, `get_declared_interfaces()`, 
> `get_declared_traits()`, but no `get_declared_enums()` [2].
>
> I'm aware that enums are internally considered classes and that 
> `get_declared_classes()` will retrieve them [1], but the same could be 
> said about interfaces and traits, yet they do have their own 
> `get_declared_*()` function.
>
> Should a `get_declared_enums()` function be added ?
> And should the `get_declared_classes()` function be adjusted to exclude enums ?
>
> I did check the enum RFC [3], but I couldn't find any mention or 
> discussion about this in the RFC.
>
> Smile,
> Juliette
>
>
> 1: https://3v4l.org/0ub6I
> 2: https://www.php.net/manual/en/ref.classobj.php
> 3: https://wiki.php.net/rfc/enumerations

Conext: I can't remember the last time I used `get_declared_classes()` (thanks to autoloading and `class_exists()` it's a kinda pointless function), so when we were working on enums it never occurred to us to think about it.  It wasn't a deliberate decision to omit, as far as I recall.

I think I'd be open to adding it; my concern would be the overlap with `get_declared_classes()`, which as you note currently would include enums, and changing that is a BC break (even if a tiny one that I doubt would impact anyone).

--Larry Garfield

---

## #124969 — Juliette Reinders Folmer — 2024-08-16T04:23:22+00:00

URL: https://externals.io/message/124937#124969 · In reply to: #124941

> 
> > […]
> Conext: I can't remember the last time I used `get_declared_classes()` (thanks to autoloading and `class_exists()` it's a kinda pointless function), so when we were working on enums it never occurred to us to think about it.  It wasn't a deliberate decision to omit, as far as I recall.
>
> I think I'd be open to adding it; my concern would be the overlap with `get_declared_classes()`, which as you note currently would include enums, and changing that is a BC break (even if a tiny one that I doubt would impact anyone).
>
> --Larry Garfield
>

Thanks for the response. It was exactly a (custom) autoloader situation 
which caused me to start wondering about this.

---

## #124970 — Mike Schinkel — 2024-08-16T05:58:02+00:00

URL: https://externals.io/message/124937#124970 · In reply to: #124941

> 
> Should a `get_declared_enums()` function be added ?

My answer is "very much, yes."

> 
> Context: I can't remember the last time I used `get_declared_classes()` (...it's a kinda pointless function)

Your experience is one data point. Another data point is my experience that it is fortunate that `get_declared_classes()` exists as I find it to be a very a useful function. The core library I use for most projects depends on it for class initialization. 

Your comment made me curious to see if others use it, and there are 8.1k uses on GitHub: 

- https://github.com/search?q=language%3Aphp+get_declared_classes&type=code

Here is how I have used, in a greatly simplified example:

function autoload($class) {
   $classCount = count(get_declared_classes());
   if (!file_exists("src/{$class}.php")) {
     return;
   }
   include_once "src/{$class}.php";
   foreach (get_declared_classes() as $class) {
     if (!method_exists($class,'init')) {
       continue;
     }
     $class::init();
   }
}

As an aside, for this use-case I have always wanted PHP to add both 1.) a `get_declared_class_count()` function and 2) optional parameters for `get_declared_classes()` that would allow requesting a subset of classes, such as just the newly added classes. How important this is depends on if PHP maintains that array internally and just returns a reference, or if it instantiates memory and populates the array of classes to return every time the function is called.

> , so when we were working on enums it never occurred to us to think about it.  It wasn't a deliberate decision to omit, as far as I recall.
> 
> I think I'd be open to adding it; my concern would be the overlap with `get_declared_classes()`, which as you note currently would include enums, and changing that is a BC break (even if a tiny one that I doubt would impact anyone).

Add another parameter — or include as part of the args array — something like this (though I am sure this could be bikeshed to be better):

get_declared_classes(DeclaredClasses:ONLY_CLASSES, ['starting_from'=>174]);
get_declared_classes(DeclaredClasses:ALL, ['recently_declared'=>3]);

Or even:

DeclaredSymbols::get_classes([$args])  <-- returns only classes, not enums
DeclaredSymbols::get_enums([$args])
DeclaredSymbols::get_interfaces([$args])
DeclaredSymbols::get_traits([$args])
#fwiw

> 
> Thanks for the response. It was exactly a (custom) autoloader situation which caused me to start wondering about this.

Seems Juliette's use-case may be at least somewhat similar to mine.

-Mike

---

## #124972 — drealecs@gmail.com — 2024-08-16T10:12:34+00:00

URL: https://externals.io/message/124937#124972 · In reply to: #124937

Hey Juliette,


> Should a `get_declared_enums()` function be added ?
>

Yes

And should the `get_declared_classes()` function be adjusted to exclude
> enums ?
>

No

You listed these entities: classes, interfaces, traits and enums.
But while there is a clear differentiation between what is considered a
class, an interface or a trait, enums are just a subtype of classes.
"all enums are classes, but not all classes are enums."

So for keeping this valid, `get_declared_classes()` should return all
classes (including enums).
While `get_declared_enums()` should return all enums.

If one really wants all classes except enums, they could use `array_diff(
 `get_declared_classes()`, get_declared_enums()`.
This would avoid the backward compatibility issues that Larry also
mentioned.

Regards,
Alex

---

## #124973 — Christoph M. Becker — 2024-08-16T11:13:51+00:00

URL: https://externals.io/message/124937#124973 · In reply to: #124937

> Should a `get_declared_enums()` function be added ?

Here we go:

    function get_declared_enums() {
        $enums = [];
        $exts = get_loaded_extensions(false);
        foreach ($exts as $ext) {
            $re = new ReflectionExtension($ext);
            $classes = $re->getClasses();
            foreach ($classes as $class) {
                if ($class->isEnum()) {
                    $enums[] = $class->name;
                }
            }
        }
        return $enums;
    }

Porting this to C is left as an excercise for the reader. ;)  Hint:
<https://github.com/php/php-src/blob/8853cf3ae950a1658054f286117bc8f77f724f00/Zend/zend_builtin_functions.c#L1371-L1399>

Note that the terminating folding marker is backwards.

> And should the `get_declared_classes()` function be adjusted to exclude
> enums ?

For reasons that have been stated elsewhere in this thread, I don't
think so.

Cheers,
Christoph

---

## #124978 — Ayesh Karunaratne — 2024-08-16T15:01:34+00:00

URL: https://externals.io/message/124937#124978 · In reply to: #124973

> Porting this to C is left as an excercise for the reader. ;)  Hint:
> <https://github.com/php/php-src/blob/8853cf3ae950a1658054f286117bc8f77f724f00/Zend/zend_builtin_functions.c#L1371-L1399>
>

I went ahead and created PR https://github.com/php/php-src/pull/15443
along with tests, UPGRADE notice, etc.

I think having a `get_declared_enums` function will be helpful. The
implementation is simple and straightforward too.

---

## #124980 — Nicolas Grekas — 2024-08-16T15:11:29+00:00

URL: https://externals.io/message/124937#124980 · In reply to: #124973

> Should a `get_declared_enums()` function be added ?
>
> Here we go:
>
>     function get_declared_enums() {
>         $enums = [];
>         $exts = get_loaded_extensions(false);
>         foreach ($exts as $ext) {
>             $re = new ReflectionExtension($ext);
>             $classes = $re->getClasses();
>             foreach ($classes as $class) {
>                 if ($class->isEnum()) {
>                     $enums[] = $class->name;
>                 }
>             }
>         }
>         return $enums;
>     }
>
> Porting this to C is left as an excercise for the reader. ;)  Hint:
> <
> https://github.com/php/php-src/blob/8853cf3ae950a1658054f286117bc8f77f724f00/Zend/zend_builtin_functions.c#L1371-L1399
> > […]
>
> Note that the terminating folding marker is backwards.
>
> > […]
>
> For reasons that have been stated elsewhere in this thread, I don't
> think so.
>


And here is a one liner:

    function get_declared_enums() {
         return array_filter(get_declared_classes(), 'enum_exists');
    }

---

## #124981 — Christoph M. Becker — 2024-08-16T15:43:59+00:00

URL: https://externals.io/message/124937#124981 · In reply to: #124980

> > […]
>
> And here is a one liner:
>
>     function get_declared_enums() {
>          return array_filter(get_declared_classes(), 'enum_exists');
>     }

Nice!

Are you suggesting that there is no need for get_declared_enums() in the
core, since it can be implemented in userland with a single function call?

If so, I still would argue that it makes sense to implement the function
in the core for (a) consistency, and (b) performance reasons.

Cheers,
Christoph

---

## #124982 — Christoph M. Becker — 2024-08-16T15:45:11+00:00

URL: https://externals.io/message/124937#124982 · In reply to: #124978

> > […]
>
> I went ahead and created PR https://github.com/php/php-src/pull/15443
> along with tests, UPGRADE notice, etc.

Thank you very much!

> I think having a `get_declared_enums` function will be helpful. The
> implementation is simple and straightforward too.

I concur.

Christoph

---

## #124983 — Bilge — 2024-08-16T15:50:13+00:00

URL: https://externals.io/message/124937#124983 · In reply to: #124981

> On 16.08.2024 at 17:11, Nicolas
> > […]
>
> Nice!
>
> Are you suggesting that there is no need for get_declared_enums() in the
> core, since it can be implemented in userland with a single function call?
>

I think he just compulsively golfs inefficient PHP code (I have the same
affliction).

Cheers,
Bilge

---

## #124984 — Nicolas Grekas — 2024-08-16T15:56:52+00:00

URL: https://externals.io/message/124937#124984 · In reply to: #124983

> On 16.08.2024 at 17:11, Nicolas
> > […]
>
> Nice!
>
> Are you suggesting that there is no need for get_declared_enums() in the
> core, since it can be implemented in userland with a single function call?
>

> I think he just compulsively golfs inefficient PHP code (I have the same
> affliction).
>

Possibly :D

I shared this as food for thoughts. I'm not convinced this function would
be useful personally, but that's not really an argument ;)

---

## #125010 — Mike Schinkel — 2024-08-17T00:00:55+00:00

URL: https://externals.io/message/124937#125010 · In reply to: #124973

To everyone on this thread and thus nobody in specific (hence my top post):

Given that get_declared_*() populates a new ZEND_HASH each time the function is called[1] — which for classes can easily be hundreds of strings — would there be any appetite to: 

1. Add an optional parameter — e.g. `get_declared_classes($startingFrom)` — that can limit the number of symbols starting with "n"  where if n==100 then it would return array_slice($symbols,100), and 

2. Add a function — `get_declared_class_count()` — that returns the current number of declared symbols of whichever kind of symbol, so we can get the "n" before calling `include`/`require` to use with get_declared_*() after calling  `include`/`require`?

Used in a (very simplistic) example:

function autoload($class) {
   $startingFrom = get_declared_class_count();
   if (!file_exists("src/{$class}.php")) {
     return;
   }
   include_once "src/{$class}.php";
   foreach (get_declared_classes($startingFrom) as $class) {
     if (!method_exists($class,'init')) {
       continue;
     }
     $class::init();
   }
}

This would cut down on creating hashes with 100+ strings that get immediately thrown away, and also cut down on memory fragmentation/garbage collector churn. 

-Mike

[1] https://github.com/php/php-src/blob/18d41502da0da1bb3928e60c41f1b821974c2c01/Zend/zend_builtin_functions.c#L1371


> 
> 
> 
> 
> > […]
> 
> Here we go:
> 
>    function get_declared_enums() {
>        $enums = [];
>        $exts = get_loaded_extensions(false);
>        foreach ($exts as $ext) {
>            $re = new ReflectionExtension($ext);
>            $classes = $re->getClasses();
>            foreach ($classes as $class) {
>                if ($class->isEnum()) {
>                    $enums[] = $class->name;
>                }
>            }
>        }
>        return $enums;
>    }
> 
> Porting this to C is left as an excercise for the reader. ;)  Hint:
> <https://github.com/php/php-src/blob/8853cf3ae950a1658054f286117bc8f77f724f00/Zend/zend_builtin_functions.c#L1371-L1399>
> 
> Note that the terminating folding marker is backwards.
> 
> > […]
> 
> For reasons that have been stated elsewhere in this thread, I don't
> think so.
> 
> Cheers,
> Christoph

---

## #125017 — Juliette Reinders Folmer — 2024-08-17T00:53:26+00:00

URL: https://externals.io/message/124937#125017 · In reply to: #124978

> I went ahead and created PR https://github.com/php/php-src/pull/15443 
> along with tests, UPGRADE notice, etc. I think having a 
> `get_declared_enums` function will be helpful. The implementation is 
> simple and straightforward too. 

Thanks for creating the PR Ayesh!

I'm presuming it's too late for PHP 8.4, what with feature freeze having 
come & gone this week.

Based on the mostly supportive responses on the list, I wonder whether 
an RFC is needed. If so, I'd be happy to create an initial draft (for 
PHP 8.5).

Smile,
Juliette

---

## #125018 — Juliette Reinders Folmer — 2024-08-17T01:25:32+00:00

URL: https://externals.io/message/124937#125018 · In reply to: #125010

> To everyone on this thread and thus nobody in specific (hence my top post):
>
> Given that get_declared_*() populates a new ZEND_HASH each time the function is called[1] — which for classes can easily be hundreds of strings — would there be any appetite to:
>
> 1. Add an optional parameter — e.g. `get_declared_classes($startingFrom)` — that can limit the number of symbols starting with "n"  where if n==100 then it would return array_slice($symbols,100), and
>
> 2. Add a function — `get_declared_class_count()` — that returns the current number of declared symbols of whichever kind of symbol, so we can get the "n" before calling `include`/`require` to use with get_declared_*() after calling  `include`/`require`?
>
>
> This would cut down on creating hashes with 100+ strings that get immediately thrown away, and also cut down on memory fragmentation/garbage collector churn.
>
> -Mike
>
> [1] https://github.com/php/php-src/blob/18d41502da0da1bb3928e60c41f1b821974c2c01/Zend/zend_builtin_functions.c#L1371
>

Mike,

While your suggestion does not directly relate to what triggered my mail 
to the list, I very very much like the idea.

It's as if you are reading my mind or rather, reading one of the 
autoloaders [1] I need to maintain, in which your above outlined 
proposal should definitely make for more efficiency.

Having said that, the same parameter + extra function would then also be 
needed for `get_declared_interfaces()`, `get_declared_traits()` - and, 
if it would be added, `get_declared_enums()`.

There is one problem I can see with this approach though: since PHP 7.4, 
the return value of `get_declared_classes()` (and friends) does not 
guarantee any particular order anymore [2].
So, an `array_slice($symbols, $n)` may not get you the _latest_ classes 
loaded, so I think this would only work if the order of classes is 
guaranteed in some way.

Smile,
Juliette

1: 
https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/6fbbc1078094d905f0773421f13830744a144d1e/autoload.php#L153-L247
2: 
https://www.php.net/manual/en/function.get-declared-classes.php#refsect1-function.get-declared-classes-changelog

---

## #125021 — Ayesh Karunaratne — 2024-08-17T04:26:11+00:00

URL: https://externals.io/message/124937#125021 · In reply to: #125017

>
> I'm presuming it's too late for PHP 8.4, what with feature freeze having come & gone this week.
>
> Based on the mostly supportive responses on the list, I wonder whether an RFC is needed. If so, I'd be happy to create an initial draft (for PHP 8.5).
>

Thank you!

We now have the Release Cycle Update RFC approved
(https://wiki.php.net/rfc/release_cycle_update#allow_features_that_do_not_require_an_rfc_in_the_beta_period),
and it does allow minor new features during the beta period.

Quoting from the RFC:

> [snip]
> It therefore seems illogical to allow RFC-requiring features to be merged during the beta period, but not minor improvements that do not require an RFC, such as adding constant, parameters, config options, or even small functions or methods.
>
> We propose to explicitly allow minor features, optimizations, and internal API / ABI changes, during the beta period.

I think the `get_declared_enums` is small enough to be considered a
minor change given we don't change any engine internals. Given the
positive response on the mailing list, I think we can have this in PHP
8.4 as well, subject to RMs approval of course. There's also a PR from
yesterday (https://github.com/php/php-src/pull/15446) that added a new
Curl constant.

---

## #125022 — Mike Schinkel — 2024-08-17T04:54:07+00:00

URL: https://externals.io/message/124937#125022 · In reply to: #125018

Hi Juliette,

> 
> 
> 
> > […]
> 
> Mike,
> 
> While your suggestion does not directly relate to what triggered my mail to the list, I very very much like the idea.

Excellent!

> It's as if you are reading my mind or rather, reading one of the autoloaders [1] I need to maintain, in which your above outlined proposal should definitely make for more efficiency.

Thank you for sharing that.  Yes, your use-case is very similar to mine. 

> Having said that, the same parameter + extra function would then also be needed for `get_declared_interfaces()`, `get_declared_traits()` - and, if it would be added, `get_declared_enums()`.

That was my assumption and intention, but I did not say so explicitly. I should have.

Thanks to Ayesh's excellent PR, I was able to recognize that all of those functions in-fact are implemented via one internal function `get_declared_class_impl()` so it only made sense — to me, at least — that modifying it would enable the same functionality for all four (4) userland functions.

> There is one problem I can see with this approach though: since PHP 7.4, the return value of `get_declared_classes()` (and friends) does not guarantee any particular order anymore [2].
> So, an `array_slice($symbols, $n)` may not get you the _latest_ classes loaded, so I think this would only work if the order of classes is guaranteed in some way.

That is a super relevant insight and one I was actually not aware of.

Do you happen to know if it was triggered by an explicit RFC to that effect, or if it resulted because of a side-effect of some other implementation change?  From my perspective, that is definitely a BC break and one that I am surprised I never noticed before?  Do you also know if it is a case of "not guaranteed, but in-fact actual fact it always works that way, or not?"  

I have not used my lib that needs that functionality to work in a few years, so maybe it is broken now and those who are now maintaining those apps have had to deal with it?

Given that you see value in the same use-case I had which was an autoloader, maybe it would be better to achieve the functionality we need in a different, more efficient way?  

What if instead PHP were to implement an optional 2nd callback parameter to `include()` / `require()` / `include_once()` / `require_once()` to allow us to capture the symbols loaded and their paths? The callback function could return `void` and accept an array of `$symbols` with the following guaranteed minimum structure?

$symbols = array(
   'classes' => [],
   'interfaces' => [],
   'traits' => [],
   'enums' => [],
);

With that you could reimplement all that PHP code you linked — at least for versions of PHP supporting the callback — to look like this:

function loadFile($path)
{
   if (strpos(__DIR__, 'phar://') !== 0) {
     $path = realpath($path);
     if ($path === false) {
       return false;
     }
   }
   if (isset(self::$loadedClasses[$path]) === true) {
     return self::$loadedClasses[$path];
   }
   include($path, function($symbols) use ($path) {
     foreach ($symbols['classes'] as $className) {
       self::$loadedClasses[$path]    = $className;
       self::$loadedFiles[$className] = $path;
     }
   });
   return self::$loadedClasses[$path];
}//end loadFile()

This approach would be a less disruptive than my prior suggestion which would have added four (4) new `*_count()` functions and new optional parameters for four (4) existing function vs. this proposal which just adds new optional parameters for four (4) other existing functions. Further, and the signature(s) required for parameters would be much easier to settle on.  

I checked the code[2] and if I understand it correctly would (only?) require adding a Zend Observer[3] callback to be notified in `zend_bind_class_in_slot()` although I still cannot figure out where that observer would need to be added.

Going this approach would also make the userland code in PHPCodeSniffer a lot more efficient than the code you currently must run for every included file simply to determine what symbols were loaded.

What do you think if this alternate approach?

-Mike 

[1] https://github.com/php/php-src/blob/18d41502da0da1bb3928e60c41f1b821974c2c01/Zend/zend_builtin_functions.c#L1371
[2] https://github.com/php/php-src/blob/php-8.3.10/Zend/zend_compile.c#L1231-L1269
[3] https://www.linkedin.com/advice/3/what-some-best-practices-common-pitfalls-using-zend

---

## #125023 — Juliette Reinders Folmer — 2024-08-17T05:36:26+00:00

URL: https://externals.io/message/124937#125023 · In reply to: #125022

Hi Mike,

>
> > […]
> That is a super relevant insight and one I was actually not aware of.
>
> Do you happen to know if it was triggered by an explicit RFC to that effect, or if it resulted because of a side-effect of some other implementation change?
I honestly don't know, but if I look through the PHP 7.4 RFC list, I 
have a niggling suspicion it may have something to do with the 
Preloading RFC [1] ? I may very well be wrong though.

>  From my perspective, that is definitely a BC break and one that I am surprised I never noticed before?  Do you also know if it is a case of "not guaranteed, but in-fact actual fact it always works that way, or not?"

Well, for the autoloader I previously linked to [2], it was a 
problematic change which we did have to work around, see [3] and [4] for 
details of the issues we saw (parent class vs child class order 
reversals, issues when multiple classes were declared in one file).

I haven't deep-dived into the order change, other than to validate the 
reported issues and proposed fixes.

> What if instead PHP were to implement an optional 2nd callback parameter to `include()` / `require()` / `include_once()` / `require_once()` to allow us to capture the symbols loaded and their paths? The callback function could return `void` and accept an array of `$symbols` with the following guaranteed minimum structure?
>
> $symbols = array(
>     'classes' => [],
>     'interfaces' => [],
>     'traits' => [],
>     'enums' => [],
> );

Except `include()` and friends aren't function calls, but language 
constructs/expressions and don't take parameters as such, so I don't see 
how that would be possible without changing `include()` and friends to 
function calls (along the lines of what happened for `exit` in PHP 8.4 
with non-parenthesized use still possible to mitigate the otherwise huge 
breaking change), or alternatively, introducing wrapper functions for 
the language constructs - so no change to the existing functionality, 
but new functions with a signature along the lines of 
`include_and_get_symbols( $path ): array` with the return value being 
the symbols loaded from $path.

> This approach would be a less disruptive than my prior suggestion

Not so sure about that considering the above ;-)
> What do you think if this alternate approach?

This probably needs some more bike shedding ;-)

Smile,
Juliette


1: https://wiki.php.net/rfc/preload
2: 
https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/6fbbc1078094d905f0773421f13830744a144d1e/autoload.php#L153-L247
3: https://github.com/squizlabs/PHP_CodeSniffer/pull/3130
4: https://github.com/squizlabs/PHP_CodeSniffer/issues/3145

---

## #125024 — Juliette Reinders Folmer — 2024-08-17T05:38:45+00:00

URL: https://externals.io/message/124937#125024 · In reply to: #125021

> I think the `get_declared_enums` is small enough to be considered a 
> minor change given we don't change any engine internals. Given the 
> positive response on the mailing list, I think we can have this in PHP 
> 8.4 as well, subject to RMs approval of course.

I'll keep my fingers crossed ;-)

---

## #125027 — Larry Garfield — 2024-08-17T13:17:32+00:00

URL: https://externals.io/message/124937#125027 · In reply to: #125017

> 
> > […]
> Thanks for creating the PR Ayesh!
>
> I'm presuming it's too late for PHP 8.4, what with feature freeze 
> having come & gone this week.
>
> Based on the mostly supportive responses on the list, I wonder whether 
> an RFC is needed. If so, I'd be happy to create an initial draft (for 
> PHP 8.5).
>
> Smile,
> Juliette

I would prefer to have an RFC for this, even if it's short.  I'm not against it, I just think there's enough non-trivial questions (eg, impact on `get_declared_classes()`) that it warrants an RFC process/discussion.

--Larry Garfield

---

## #125028 — Claude Pache — 2024-08-17T17:31:40+00:00

URL: https://externals.io/message/124937#125028 · In reply to: #125027

> Le 17 août 2024 à 15:17, Larry Garfield <larry@garfieldtech.com> a écrit :
> 
> 
> > […]
> 
> I would prefer to have an RFC for this, even if it's short.  I'm not against it, I just think there's enough non-trivial questions (eg, impact on `get_declared_classes()`) that it warrants an RFC process/discussion.
> 
> --Larry Garfield

Hi,

I concur with Larry, it should not be rushed into PHP 8.4, but carefully considered if it is really the correct function to define. Enums were introduced three years ago, and until three days ago, there has been apparently no complaint of the missing function, and it has been proposed less because of a need than because of an apparent lack of symmetry with other `get_declared_*()` functions. So, there is no urgency.

Now, the proposed design for `get_declared_enums()` is problematic, because it will bring (or sustain) confusion. An enum is (imo rightfully) considered as a class for the purpose of `class_exists(...)`; and following the same logic, the proposed `get_declared_enums()` returns (rightfully) a subset of the names returned by `get_declared_classes()`. On the other hand, in the mind of many people – as it can be seen in several messages in this thread, and citing the original poster –, there are four different OO structures in PHP: classes, interfaces, traits, and enums. For example, one is tempted to write naïvely:

```php
function get_declared_symbols(): array {
    return [ ...get_declared_classes(), ...get_declared_interfaces(), ...get_declared_traits(), ...get_declared_enums() ];
}
```

not realising that enums will appear twice in the returned list.

An alternative design that is less confusing could be the following. I am not really proposing it (as I am personally not convinced that `get_declared_classes()` filtered by `enum_exists()` is not sufficient), but I merely give it as an illustrative example of an api thought to avoid or reduce confusion. We could add an optional parameter to the existing `get_declared_classes()` function, specifying what sort of classes they are interested in:

```php
const SIMPLE_CLASS = 1;
const ABSTRACT_CLASS = 2;
const ANONYMOUS_CLASS = 4;
const ENUM = 8;

function get_declared_classes(int $type = SIMPLE_CLASS | ABSTRACT_CLASS | ANONYMOUS_CLASS | ENUM): array { /* ... */ }
```

—Claude

---

## #125039 — Mike Schinkel — 2024-08-18T04:46:09+00:00

URL: https://externals.io/message/124937#125039 · In reply to: #125023

> 
> > […]
> Except `include()` and friends aren't function calls, but language constructs/expressions and don't take parameters as such, so I don't see how that would be possible without changing `include()` and friends to function calls (along the lines of what happened for `exit` in PHP 8.4 with non-parenthesized use still possible to mitigate the otherwise huge breaking change),

I know that those functions can be called as a function and return a value like the following:

$return_value = include($path);

I was making an assumption that since they be called like a function they could also accept optional parameters, although I admittedly was only assuming and do not know for sure.  Do you know for a fact that they cannot take a 2nd parameter, or just assuming like I was?   

Does anyone else know for certain it is would be possible for `include()` et.al. to accept an optional 2nd parameter?

However, even if a 2nd parameter is not a viable option then this could be addressed by instead adding  a single new function with a signature of `spl_autoload_callback($fn callback):callback` where the callback has a signature of `function ($symbols array)` which could be used like so:

function loadFile($path)
{
   if (strpos(__DIR__, 'phar://') !== 0) {
     $path = realpath($path);
     if ($path === false) {
       return false;
     }
   }
   if (isset(self::$loadedClasses[$path]) === true) {
     return self::$loadedClasses[$path];
   }
   $prior_callback = spl_autoload_callback(function($symbols) use ($path) {
     foreach ($symbols['classes'] as $className) {
       self::$loadedClasses[$path]    = $className;
       self::$loadedFiles[$className] = $path;
     }
   });
   include($path);
   spl_autoload_callback($prior_callback);
   return self::$loadedClasses[$path];
}

> > […]
> Not so sure about that considering the above ;-)

Well then I think a single new function would be very low on the disruption scale, no?

> This probably needs some more bike shedding ;-)

Shedding of bike undertaken. :-)

-Mike

---

## #125040 — Aleksander Machniak — 2024-08-18T07:50:43+00:00

URL: https://externals.io/message/124937#125040 · In reply to: #124937

> Should a `get_declared_enums()` function be added ?

Yes

> And should the `get_declared_classes()` function be adjusted to exclude 
> enums ?

and Yes.

I'd like to see an RFC with these two questions.

-- 
Aleksander Machniak
Kolab Groupware Developer        [https://kolab.org]
Roundcube Webmail Developer  [https://roundcube.net]
----------------------------------------------------
PGP: 19359DC1 # Blog: https://kolabian.wordpress.com

---

## #125041 — Rowan Tommins [IMSoP] — 2024-08-18T08:59:07+00:00

URL: https://externals.io/message/124937#125041 · In reply to: #125039

>I know that those functions can be called as a function and return a value like the following:
>
>$return_value = include($path);

You are right that it has a return value, but wrong to put its argument in parentheses. This will *not* do what you expect: 

$success = include($path) && somethingElse();

Because include is not actually a function, what is evaluated is `$path && somethingElse()`, then either `include true` or `include false` (which will of course fail).

You instead need to write this: 

$success = (include $path) && somethingElse();

I thought I'd added this example to the manual, but now can't find it.

Consequently, we can't just define optional parameters like we would a normal function. We *could* extend the syntax to allow "include $path, $whatever;" but it probably wouldn't feel very natural. It would be a syntax error to write "include($path, $whatever)" just as "echo $foo, $bar" is valid, but "echo($foo, $bar)" is not.

Regards,
Rowan Tommins
[IMSoP]

---

## #125044 — Mike Schinkel — 2024-08-19T05:22:41+00:00

URL: https://externals.io/message/124937#125044 · In reply to: #125041

> 
> 
> 
> > […]
> 
> You are right that it has a return value, but wrong to put its argument in parentheses. This will *not* do what you expect: 
> 
> $success = include($path) && somethingElse();
> 
> Because include is not actually a function, what is evaluated is `$path && somethingElse()`, then either `include true` or `include false` (which will of course fail).
> 
> You instead need to write this: 
> 
> $success = (include $path) && somethingElse();
> 
> I thought I'd added this example to the manual, but now can't find it.
> 
> Consequently, we can't just define optional parameters like we would a normal function. We *could* extend the syntax to allow "include $path, $whatever;" but it probably wouldn't feel very natural. It would be a syntax error to write "include($path, $whatever)" just as "echo $foo, $bar" is valid, but "echo($foo, $bar)" is not.
Hi Rowan,

Thank you for confirming the nature of include, et. al.

So, if the functionality to be notified via a callback for all symbols loaded is a desired feature by other than me and maybe Juliette then the best approach I've come up with is to add an `spl_autoload_callback()` function that can both get and set the callback to be called after include or its 3 other friends are called.  Anyone (else?) disagree?

-Mike

---

Next page: https://externals.io/message/124937.md?page=2
