Skip to content

Cache ObjectAccess::forContext() using ScopedCache#57

Merged
veewee merged 1 commit intophp-soap:mainfrom
veewee:feature/object-access-cache
Mar 26, 2026
Merged

Cache ObjectAccess::forContext() using ScopedCache#57
veewee merged 1 commit intophp-soap:mainfrom
veewee:feature/object-access-cache

Conversation

@veewee
Copy link
Copy Markdown
Member

@veewee veewee commented Mar 26, 2026

Summary

ObjectAccess::forContext() rebuilds the full property mapping for a complex type on every encode/decode call: iterates all properties from metadata, detects encoders for each, creates encoder/decoder lenses, and builds isos. This is the most expensive operation on the hot path.

Now cached per (registry, namespace, typeName, bindingUse) using ScopedCache (introduced in #56).

Cache key

  • namespace|typeName: determines which type and properties are resolved from metadata
  • bindingUse: affects the iso closures (xsi:type attributes in encoded mode, XMLWriter bypass in literal)
  • registry: is the WeakMap scope (separate cache per driver instance)

Why bindingUse is in the key

The same complex type used with literal vs encoded binding produces different isos: encoded mode adds xsi:type attributes via XsiAttributeBuilder, literal mode may bypass XMLWriter entirely. A test verifies this by comparing the XML output of the same type with both bindings.

Impact (local benchmark)

Subject Main Feature Delta
Encode Literal x500 59ms 44ms -26%
Encode Encoded x500 82ms 73ms -11%
Decode Literal x500 81ms 65ms -20%
Decode Encoded x500 116ms 102ms -12%

Test plan

  • Full test suite passes (560 tests, 3 new)
  • Psalm clean
  • CS fixer clean
  • Benchmarked against main
  • Test: different bindingUse produces different ObjectAccess (different isos)
  • Test: different registries don't share cache
  • Test: same context returns cached instance

ObjectAccess::forContext() rebuilds the full property mapping for a
complex type on every encode/decode: iterates all properties, detects
encoders, creates lenses, and builds isos. Now cached per
(registry, namespace, typeName, bindingUse) using ScopedCache.

Cache key includes bindingUse because the isos capture binding-dependent
behavior (xsi:type attributes in encoded mode, XMLWriter bypass in
literal mode).

~20-25% improvement on both encode and decode paths.
@veewee veewee merged commit 15d1860 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