[3.0] Checks that every class name written as a string names something real - #9661
Open
albertlast wants to merge 1 commit into
Open
[3.0] Checks that every class name written as a string names something real#9661albertlast wants to merge 1 commit into
albertlast wants to merge 1 commit into
Conversation
A class name in a string is not a name PHP ever checks. It reaches the autoloader only at the moment it is used, which for a background task is a cron run on somebody else's forum: TaskRunner::execute() logs the class it could not find, drops the row from the queue and carries on, so the work never happens and the only trace is a line in log_errors. The test walks Sources/ and Themes/ to build the set of names the forum ships, tokenises every file to pull out the SMF\... strings it writes down, and asserts each one names a class, a namespace or a method that exists. Existence probes are skipped, since naming something that may not be there is the entire point of class_exists() and its relatives. The set is built from the file tree rather than asked of class_exists() because Composer's PSR-4 loader ends at file_exists(), which is case-insensitive on Windows and macOS. A misspelling that only differs in case would pass on two of the four legs of the unit matrix and fail on the other two. A directory entry stores the case it was created with everywhere, so a set built from the file names is exact on all of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
Member
|
Checking for this is a good idea, yes. It would also be helpful to get a separate PR that found all such strings in the current code and replaced them with |
Collaborator
Author
|
So we would like to have \SMF\Tasks\FetchSMFiles::class instead of the other way in the complet code base? |
This was referenced Sep 8, 2026
Member
|
Correct. This PR is useful in cases where we can't use |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This is red until #9660 merges, and that is the point of it. #9660 fixes a background
task queued as
'SMF\Tasks\FetchSMfiles'when the class isFetchSMFiles. This adds thetest that catches that class of typo, so the check fails on
release-3.0as it stands andgoes green the moment that one character lands. Nothing else here touches production code.
A class name written as a string is not a name PHP ever checks. It reaches the autoloader
only at the moment it is used, which for a background task is a cron run on somebody else's
forum:
TaskRunner::execute()logs the class it could not find, drops the row from thequeue and carries on. The work simply never happens, and the only trace is a line in
log_errors. Nothing in CI could see it either —phplintsees a valid string,php-cs-fixerdoes not read inside strings,Upgrade::finalize()needs a database so theunit suite cannot reach it, and the integration suite installs a fresh forum, so the
upgrader never runs.
The test walks
Sources/andThemes/to build the set of names the forum ships, tokenisesevery shipped file to pull out the
SMF\...strings written down in it, and asserts each onenames a class, a namespace or a method that exists. Run against
release-3.0it reportsexactly one thing:
That is 85 distinct class-name literals across 1,685 files, one true positive and no false
positives.
Why the set is built from the file tree instead of asking
class_exists()Composer's PSR-4 loader ends at
file_exists(), which is case-insensitive on Windows andmacOS, so
class_exists('SMF\Tasks\FetchSMfiles')returns true there. A test written theobvious way would have passed on the two Windows legs of the unit matrix and failed on the
two Linux ones, which reads as a flaky test rather than a real bug.
A directory entry stores the case it was created with on every platform — only lookup is
insensitive — so a set built from the file names is exact everywhere, and a plain string
comparison against it is case-sensitive even where the filesystem is not.
Only the class half is treated that way. Method names are checked with
method_exists(),because PHP method names really are case-insensitive and resolve through traits and parents:
Actions\Groups::callcomes fromActionTraitand is not declared in the class at all.Two things it deliberately ignores
class_exists(),function_exists()and theirrelatives is a question, not a claim. This covers the bootstrap-order checks in
Configand
IntegrationHook, the two Unicode helper probes inPunycode, and the oneproxy.phpkeeps for the benefit of old mods.
ActionRouterasks whether its own class sits under'SMF\Actions',which is a namespace and never a class. Treating every namespace along the way as a valid
name absorbs that without needing an allowlist — it is the only bare prefix in the tree.
It reads tokens rather than lines because a docblock saying
@var SMF\Utilsis not areference and there are thousands of those.
Cost
0.151s. No CI change is needed;
phpunit.ymlalready runs the unit suite on ubuntu andwindows across PHP 8.4 and 8.5, and this is exactly the sort of bug that wants all four.
Issues References (Fixes|Related|Closes)
🤖 Generated with Claude Code