08: Registrar - #8
Open
nikolaystrikhar wants to merge 3 commits into
Open
Conversation
Registration order decides load order, and nothing said so where a host would read it. A host registering an add-on before the plugin it extends gets a class-not-found fatal at plugins_loaded. Also explain on the contract why reset() is on it: a container-bound singleton registrar survives a Loader reset, so an implementation that no-ops reset() leaks registrations between boots.
… foreign registrar
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.
What: the sub-plugin registry and its contract.
Stacked on #7.
Usage:
Why this way: keyed by slug so re-registering the same slug replaces rather than duplicates — a host that conditionally registers in two code paths gets one entry, not two loads. The interface ships in this PR rather than in a contracts-only PR so it arrives with an implementation and tests.
The review found no defects in the code, but did surface an undocumented guarantee.
all()returns insertion order, andLoader::load_all()require_onces in that order — so if a host bundles an add-on whose main file extends a class defined by another sub-plugin, and registers the add-on first, they get a class-not-found fatal atplugins_loaded. Nothing said so anywhere a host would read it. The README now does.Assigning by key (rather than appending) is also what keeps a re-registration in place instead of moving it to the end, which is what makes the order stable for conditional registration. Verified:
$a["x"]=1; $a["y"]=2; $a["x"]=3leavesxat index 0. Two tests pin this; the plan's version left load order entirely unasserted.reset()sits on the interface deliberately, and now says why: a container-bound singleton registrar hands back the same populated instance after aLoaderreset, so an implementation that no-opsreset()leaks registrations between boots. A third party implementing this contract had no way to know that.Two plan fixes carried here: every remaining
private function make(...)fixture helper is renamed (four of them, in Tasks 7, 8, 9 and 13 — each would have been a compile-time fatal againstCodeception\Test\Unit::make()), andLoader::load_all()gains aninstanceof Sub_Pluginskip.Registrar_Interface::all()can only declarearray, so a host binding a registrar that returns anything else would fatal on the first predicate call insideplugins_loaded— the exact failure mode this library exists to prevent. PHPStan cannot catch that one: it trusts the interface's@return array<string,Sub_Plugin>and never analyses host code.Verify:
slic run unit— 85 tests, 120 assertions, green.composer test:analysis→[OK] No errors, exit 0.