Skip to content

Resolve the xsi:type cache key without building the detected type - #82

Merged
veewee merged 2 commits into
php-soap:mainfrom
veewee:perf-xsi-type-resolution
Oct 16, 2026
Merged

veewee merged 2 commits into
php-soap:mainfrom
veewee:perf-xsi-type-resolution

Conversation

@veewee

@veewee veewee commented Oct 15, 2026

Copy link
Copy Markdown
Member
Q A
Type improvement
BC Break no
Fixed issues

Summary

On a use=encoded response every element carries an xsi:type, and XsiTypeEncoder asks XsiTypeDetector for the matching encoder on each one. The encoder itself already comes from the ScopedCache, but to build the cache key the detector first cloned the slot type three times into the detected type and then read six meta flags from it. Those flags belong to the slot, so they are the same for every element the iso decodes.

The detector now reads the namespace and local name from the element and only builds the detected type on a cache miss. XsiTypeEncoder::iso() also gets a small detector closure from XsiTypeDetector::encoderDetectorForContext() (internal), which works out the slot flags once per iso. Per element that leaves parsing the xsi:type and the cache lookup. detectEncoderFromXmlElement() and detectXsdTypeFromXmlElement() keep their signatures and results.

Cache key

The key string is the same as on main: namespace URI, local name of the xsi:type and the slot meta flags (element, attribute, nullable, list, qualified, simple). I only build it in two halves now. It stays in the existing per registry ScopedCache, and no element value goes into it. The closure holds the slot flags and the context, nothing that grows with the payload.

Speed

phpbench, median of 3 interleaved runs, x500 subjects:

subject main this PR
Decode Encoded 48.1 ms 39.5 ms (-18%)
Encode Encoded 56.3 ms 55.6 ms (-1%)
Decode Literal 29.9 ms 30.3 ms (+1%)
ext-soap Decode Encoded (noise reference) 7.6 ms 7.9 ms (+3%)

The 3MB literal workloads also run through XsiTypeEncoder for every item, so they gain a little as well. Seconds, median of 3 interleaved rounds:

workload main this PR
decode sparse, stdClass 0.482 0.450 (-7%)
decode sparse, classmap 0.919 0.882 (-4%)
decode dense, stdClass 0.275 0.242 (-12%)
decode dense, classmap 0.346 0.304 (-12%)

Encode on the 3MB workloads stays within 3% either way.

The encoder cache key only needs the namespace, the local name and the slot meta.
I now read those from the element and only build the XsdType copy when the cache misses.
The slot part of the cache key only depends on the context, which is fixed for an iso.
XsiTypeEncoder now asks the detector for a per context detector when it builds its iso,
so decoding an element only parses the xsi:type and does the cache lookup.
@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 40 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2ccc0470-13f2-494f-a117-0d3d1b47eedb
📥 Commits

Reviewing files that changed from the base of the PR and between 403a479 and ab0e6e7.

📒 Files selected for processing: 3
  • src/Encoder/XsiTypeEncoder.php
  • src/TypeInference/XsiTypeDetector.php
  • tests/Unit/Encoder/XsiTypeEncoderTest.php
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@veewee
veewee merged commit c366aa4 into php-soap:main Oct 16, 2026
13 checks passed
@veewee
veewee deleted the perf-xsi-type-resolution branch October 16, 2026 08:49
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