Short description of the issue
Commits a7884201 and 01d6cc00 together changed two NullPage invariants:
newNullPage() now returns a pooled singleton by default (previously every call returned a fresh instance).
isChanged() now returns $this->hasSets rather than always false.
Code that compared NullPages by identity ($a === $b) or relied on NullPage as an "always clean" sentinel can now observe surprising aliasing and a non-clean state.
Expected behavior
newNullPage() returns a fresh, never-changed NullPage on every call (the historical contract).
Actual behavior
wire/core/NullPage.php:73-78 + Pages::newNullPage():
- Default behavior is to return the pooled singleton.
isChanged() returns true if set() has been called on the singleton — but the same singleton is then returned to other callers, leaking state.
Optional: Suggestion for a possible fix
Either:
- Revert the default to
forceNew=true (always-fresh) and have specific callers opt into pooling via the existing forceNew=false argument.
- Document the new pooling contract prominently as a BC break and audit core call sites that mutate NullPage via
set().
Setup/Environment
- ProcessWire version:
dev @ 15c749ed
- Files:
wire/core/NullPage.php:73-78, wire/core/Pages/Pages.php (newNullPage)
- Introduced across commits a7884201, 01d6cc00
Short description of the issue
Commits a7884201 and 01d6cc00 together changed two NullPage invariants:
newNullPage()now returns a pooled singleton by default (previously every call returned a fresh instance).isChanged()now returns$this->hasSetsrather than alwaysfalse.Code that compared NullPages by identity (
$a === $b) or relied on NullPage as an "always clean" sentinel can now observe surprising aliasing and a non-clean state.Expected behavior
newNullPage()returns a fresh, never-changed NullPage on every call (the historical contract).Actual behavior
wire/core/NullPage.php:73-78+Pages::newNullPage():isChanged()returns true ifset()has been called on the singleton — but the same singleton is then returned to other callers, leaking state.Optional: Suggestion for a possible fix
Either:
forceNew=true(always-fresh) and have specific callers opt into pooling via the existingforceNew=falseargument.set().Setup/Environment
dev@15c749edwire/core/NullPage.php:73-78,wire/core/Pages/Pages.php(newNullPage)