Hi Mike,
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?
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