Release: declare extension dependencies and default-enabled on Module (Phase 2.5) - #24387
Merged
Conversation
… (Phase 2.5) RELEASE-PLAN Phase 2.5 wants extensions to become separate, discoverable, side-loadable modules. The blocker measured in #24285: Module declares no dependencies and no default-enabled flag, so the set cannot be selected per build and the load order lives only in a hand-maintained list in Runtime::loadCoreModules(). Adds two declarations, with defaults in ModuleAbstract that preserve current behaviour exactly: getExtensionDependencies(): list<string> default [] — ordering constraints, today implicit isDefaultEnabled(): bool default true — all 76 load unconditionally now Safe to add to the interface: all 76 ext/*/Module.php extend ModuleAbstract and it is the only implementor, so nothing needs updating. Declares the libxml family, where the constraint is real and currently only remembered — php-src ext/dom, simplexml, xml, xmlreader, xmlwriter build on ext/libxml, and xsl additionally on dom: dom, simplexml, xml, xmlreader, xmlwriter -> libxml xsl -> libxml, dom A declaration nobody verifies is worse than none — it reads as authoritative while being free to drift — so script/check-extension-dependencies.php asserts every declared dependency exists, is loaded, and loads BEFORE its dependent in Runtime::loadCoreModules(). It reorders nothing; its job is to prove the declarations describe reality, which is the precondition for later deriving the order from them instead of hand-maintaining it. Validated in both directions: as declared ok — 6 extensions, 7 edges, all satisfied with dom -> xsl (xsl loads later) FAILED: dom (load #6) declares dependency "xsl" but xsl loads later at #7 exit 1 Nothing consumes isDefaultEnabled() yet. The declaration comes first so the set can be made selectable without a flag day. Gate (touches lib/Module.php and lib/ModuleAbstract.php, which every extension implements), branch vs a clean master checkout, run sequentially, both cold, waiting for each sweep to COMPLETE before diffing: cold aot-smoke : 8/8 both sides VM --repeat 2 : 110/110 both sides, exit 0 AOT --repeat 3 : master 18 failing, branch 18 failing regressions (branch-only): NONE fixed (master-only) : NONE Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Jul 28, 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.
Next increment of Phase 2.5, after the measurement in #24285.
The blocker this removes
Moduledeclares no dependencies and no default-enabled flag. So the extension set cannot beselected per build, and the load order exists only as a hand-maintained list in
Runtime::loadCoreModules()where the constraints are real but implicit.What this adds
Two declarations, with defaults in
ModuleAbstractthat preserve current behaviour exactly:Safe to add to the interface: all 76
ext/*/Module.phpextendModuleAbstract, and it is the onlyimplementor, so nothing needs updating.
Declaring the libxml family
php-src
ext/dom,simplexml,xml,xmlreader,xmlwriterbuild onext/libxml;xsladditionally on
dom:These are exactly the constraints the hardcoded order already satisfies — the point is to make them
checkable rather than remembered.
A declaration nobody verifies is worse than none
It reads as authoritative while being free to drift.
script/check-extension-dependencies.phpasserts every declared dependency exists, is loaded, and loads before its dependent. It reorders
nothing — proving the declarations describe reality is the precondition for later deriving the
order from them.
Validated in both directions:
Deliberately not done yet
Nothing consumes
isDefaultEnabled().Runtime::loadCoreModules()is untouched — the 76 hardcodedloads are still there, in the same order.
That is on purpose: the loop instruction for this work is to prove a generated order is identical to
the hardcoded one before anything becomes selectable, and the declarations have to exist and be
verified first. Making the set selectable in the same change would mean shipping an unverified
reordering of the thing every extension depends on.
Gate
Touches
lib/Module.phpandlib/ModuleAbstract.php, which every extension implements. Branch vs aclean master checkout, run sequentially, both cold, each sweep allowed to complete before
diffing:
aot-smoke--repeat 2--repeat 3