Skip to content

Cache xsi:type encoder detection in XsiTypeDetector#56

Merged
veewee merged 3 commits intophp-soap:mainfrom
veewee:feature/xsi-type-detector-cache
Mar 26, 2026
Merged

Cache xsi:type encoder detection in XsiTypeDetector#56
veewee merged 3 commits intophp-soap:mainfrom
veewee:feature/xsi-type-detector-cache

Conversation

@veewee
Copy link
Copy Markdown
Member

@veewee veewee commented Mar 26, 2026

Summary

Introduces ScopedCache (src/Cache/ScopedCache.php): a generic, GC-safe WeakMap-based cache scoped to an object's lifetime. When the scope object is garbage collected, all its cached entries are released. Marked @internal.

XsiTypeDetector: caches the full FixedIsoEncoder per (registry, namespace, typeName, meta fingerprint). The meta fingerprint includes isElement, isAttribute, isNullable, isList, and isQualified. This eliminates both encoder detection and iso rebuilding on the decode hot path for repeated xsi:type values.

EncoderDetector: refactored from inline WeakMap to use ScopedCache (same behavior, consistent pattern).

Cache key design

The cache key is namespace|typeName plus a meta fingerprint of 5 bits that affect the encoder's iso() behavior. These were identified by tracing every $meta-> access in encoder iso() methods:

  • isElement / isAttribute: read by ErrorHandlingEncoder::iso()
  • isNullable: read by ObjectAccess, AnyElementEncoder::iso()
  • isList: read by ObjectEncoder::from(), AnyElementEncoder::iso()
  • isQualified: read by ElementBuilder (encode path, captured in iso closures)

Other XsdType properties (targetNodeName, targetNamespace) vary per property but only affect the encode direction. Since the cached FixedIsoEncoder is only used for decode (from XsiTypeEncoder::from()), they don't need to be in the key.

Impact

~34% improvement on encoded decode path (113ms to 75ms for 500 items). Literal decode and all encode paths are unaffected.

Test plan

  • Full test suite passes (552 tests, 3 new)
  • Psalm clean
  • CS fixer clean
  • Benchmarked against main: -34% decode encoded, no regression elsewhere
  • 16 existing ImpliedSchema tests exercise xsi:type with different meta combinations
  • 3 new tests: nullable vs non-nullable same xsi:type, separate registries, list vs non-list

veewee added 3 commits March 26, 2026 14:30
Introduces ScopedCache: a generic, GC-safe WeakMap-based cache scoped
to an object's lifetime. Used by XsiTypeDetector and EncoderDetector.

XsiTypeDetector now caches the full FixedIsoEncoder per
(registry, namespace, typeName, meta fingerprint). The meta fingerprint
includes isElement, isAttribute, isNullable, isList, and isQualified.
This eliminates both encoder detection and iso rebuilding on the decode
hot path for repeated xsi:type values.

EncoderDetector refactored to use ScopedCache (replaces inline WeakMap).

~34% improvement on encoded decode path.
@veewee veewee merged commit 8dbfbbc into php-soap:main Mar 26, 2026
16 checks passed
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.

1 participant