Skip to content

Release: declare extension dependencies and default-enabled on Module (Phase 2.5) - #24387

Merged
PurHur merged 1 commit into
masterfrom
release/module-declarations
Jul 28, 2026
Merged

Release: declare extension dependencies and default-enabled on Module (Phase 2.5)#24387
PurHur merged 1 commit into
masterfrom
release/module-declarations

Conversation

@PurHur

@PurHur PurHur commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Next increment of Phase 2.5, after the measurement in #24285.

The blocker this removes

Module declares no dependencies and no default-enabled flag. So the extension set cannot be
selected 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 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.

Declaring the libxml family

php-src ext/dom, simplexml, xml, xmlreader, xmlwriter build on ext/libxml; xsl
additionally on dom:

dom, simplexml, xml, xmlreader, xmlwriter  ->  libxml
xsl                                        ->  libxml, 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.php
asserts 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:

as declared                        ok — 6 extensions, 7 edges, all satisfied by the load order
with dom -> xsl (xsl loads later)  FAILED: dom (load #6) declares dependency "xsl"
                                           but xsl loads later at #7          exit 1

Deliberately not done yet

Nothing consumes isDefaultEnabled(). Runtime::loadCoreModules() is untouched — the 76 hardcoded
loads 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.php and lib/ModuleAbstract.php, which every extension implements. Branch vs a
clean master checkout, run sequentially, both cold, each sweep allowed to complete before
diffing:

branch master
cold aot-smoke 8/8 8/8
VM --repeat 2 110/110, exit 0 110/110, exit 0
AOT --repeat 3 18 failing 18 failing
regressions (branch-only): NONE
fixed (master-only)      : NONE

… (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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants