[3.0] Writes class names as ::class resolvers rather than strings - #9665
Merged
Sesquipedalian merged 1 commit intoSep 8, 2026
Merged
Sesquipedalian merged 1 commit into
Sesquipedalian merged 1 commit into
Conversation
A class name in a string is not a name PHP ever checks. Every one that names a class SMF ships is now written as a ::class resolver, so the compiler resolves it against the file's imports and a misspelling stops being invisible. Where the value is a callable or a name that other code parses, the class half becomes a resolver and the rest stays a string, so every value is byte for byte what it was. The upgrader's FetchSMfiles is the exception: writing it as a resolver spells it the only way it can be spelled, which is the fix in SimpleMachines#9660. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
Sesquipedalian
approved these changes
Sep 8, 2026
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
Follow-up to the review comment on #9661, which asked for a separate PR replacing every
class name written as a string with a
::classresolver.A name in a string is not a name PHP ever checks.
phplintsees a valid string,php-cs-fixerdoes not read inside strings, and nothing resolves the name until the momentit is used — which for a background task is a cron run on somebody else's forum, where
TaskRunner::execute()logs the class it could not find, drops the row and carries on.Written as
Tasks\CreatePost_Notify::class, the compiler resolves the name against thefile's imports, so a misspelling is a name that is simply not there, and an IDE renaming
the class renames this too.
103 literals across 47 files. Four are deliberately left alone, and each is the same kind of
thing:
ActionRouterasks whether its own class sits under'SMF\Actions', which is anamespace and never a class;
Sources/Actions/Admin/PackageManager.phpnames the aliasclass_alias()is about to create, which is not a class until it does; andPunycodeprobesfor two Unicode helper functions, which have no resolver.
Nothing changes shape
A
Class::methodstring is a callable, and in several places it is also a string that SMFitself parses:
Moderation\Main::buildRoute()doesstr_contains($area['function'], '::')and then
substr()to pull the class out, andProfile\Mainfalls an area'sfunctionbackinto
Utils::$context['sub_template']. So the class half becomes a resolver and the reststays a string:
[Foo::class, 'method']andFoo::method(...)were both on the table and both were dropped:they change the value's type, these tables travel through
integrate_*hooks, and theconcatenation is what the neighbouring entries already look like
(
'function' => __NAMESPACE__ . '\Home::call'). Happy to switch if reviewers prefer one.There is one deliberate difference in the whole diff.
Upgrade.phpqueued'SMF\Tasks\FetchSMfiles'when the class isFetchSMFiles; writing it as a resolver spellsit the only way it can be spelled, so this line also carries the fix in #9660. Whichever
merges second gets a one-line conflict.
One line reads fully qualified rather than imported.
TrackIP.phpalready importsSMF\Profile\Tracking, a class that does not exist anywhere in the tree, and that deadimport shadows
Profile\Tracking, so\SMF\Actions\Profile\Tracking::classis spelled out.Removing the dead import belongs in its own change.
How it was checked
The rewrite was mechanical, and so was the check on it. A script resolves every
::classreference in the new tree the way PHP does — walking the file's
namespaceand its imports,with an import beating the current namespace — and compares the result against the string
that used to be at that spot. Every one matches, the
FetchSMfilescorrection aside. Thatcaught a real bug on the first pass:
Profile\Tracking::classinTrackIP.phphad silentlybecome
SMF\Profile\Trackingbecause of the import above.Then, on the running forum:
composer lintclean,php -lon all 47,composer testgreen(350 tests), and a sweep of the pages this touches with nothing in
log_errors— boardindex, the admin areas for packages, membergroups, holidays, scheduled tasks and the error
log, profile drafts, tracking, moderation, reported posts, the three feeds, a board and a
topic. Posting a reply queued
SMF\Tasks\CreatePost_Notify, byte for byte the string itqueued before, and cron ran it without complaint.
Issues References (Fixes|Related|Closes)
Upgrade.phpline 1229 carries that fix as a consequence.🤖 Generated with Claude Code