feat: make the algorithm, checker and serializer managers immutable - #703
Merged
Conversation
A manager expresses a policy ("these algorithms and no others"), so it must
not be possible for a consumer to widen it. AlgorithmManager::add() mutated a
service that is usually shared: it is deprecated in favour of with(), which
returns a new manager and leaves the current one untouched.
The state of the checker and serializer managers is now readonly, and both
serializer managers, already final, are readonly classes.
Spomky
force-pushed
the
feature/immutable-managers
branch
from
August 29, 2026 16:39
5dfc8e3 to
2d5fa88
Compare
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.
Target branch: 4.3.x
Resolves issue #688
Includes:
A manager expresses a policy — "these algorithms and no others".
AlgorithmManager::add()let any consumer holdingthe injected service widen that policy for every other consumer, so it is deprecated in favour of an immutable API.
AlgorithmManagerwith(Algorithm ...$algorithms): selfreturns a new manager supporting the current algorithms plus the given ones.An algorithm whose name is already supported replaces the previous one, as
add()did.add()still works and still mutates, but triggers a deprecation. The constructor does not go through it any more,so building a manager is silent.
$algorithmsstays writable:readonlythere would break the deprecatedadd().The other managers
HeaderCheckerManager,ClaimCheckerManager,JWSSerializerManagerandJWESerializerManageralready had a privateadd(), so they only needed their state closed: the properties are nowreadonlyand filled once by the constructor,and the now-unused private
add()/addTokenTypeSupport()methods are gone. Both serializer managers, alreadyfinal,became
readonlyclasses (asked for by Rector, and equivalent here since they hold a single property).The two checker managers stay non-
final: the bundle extends them to dispatch events. Their docblock records thatthey will be
finalin 5.0.0.No public signature changed and no behaviour changed for existing callers, so nothing breaks.
with()wasdeliberately not added to the four other managers: their
add()was never public, and 5.0.0 is where the whole familygets the same treatment.
Tests
AlgorithmManagerTestcoverswith()(new instance, original untouched, several algorithms at once, replacement byname, no deprecation) and
add()(deprecation triggered, mutation preserved).ImmutableManagerStateTestasserts the state of the four other managers isreadonly, so a later change cannotquietly reopen it.
Full suite, ECS, PHPStan, Rector and Deptrac are green; the managers were also smoke-tested on PHP 8.2, the minimum
supported version, for the
readonly classsyntax.