fix: Emit resource constructor parameters required first - #473
Merged
Conversation
Resource constructor parameters were ordered by property name alone, so an optional property, one carrying a null default, could be declared ahead of a required one. PHP deprecates that ordering, which made every optional default inert, and PHP 9 is expected to make it fatal. Loading the resource classmap emitted 409 E_DEPRECATED notices across 26 of the 32 files. None of the tooling saw them: psalm and phpunit both exclude src/Resources, and phpunit routes deprecations to a channel failOnWarning does not cover, so the suite stayed green through all of them. Nor is it only cosmetic. composer lint:syntax shells out to php -l, so it fails on any host whose error_reporting includes E_DEPRECATED, which is PHP's own default when no php.ini is loaded. Emit required properties first and optional ones after, alphabetical within each group, the same shape the route generator already produces for endpoint parameters. Which properties are required stays the blueprint's call, read from isOptional, rather than being flattened by giving everything a default. from_json passes every value by name, so it is unaffected. Turn on failOnDeprecation so this cannot come back unnoticed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HH3wdHh4Y6Wjyc5uHwk5iG
razor-x
force-pushed
the
claude/php-audit-uoa7nb-m8-resource-param-order
branch
from
August 19, 2026 21:22
eef6fa4 to
a319a2b
Compare
This was referenced Aug 19, 2026
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.
Fixes finding M8 from the cross-SDK audit.
Rebased onto
betaata2cd8ce(4.0.0-beta.13) and regenerated, so the conflict is gone.The problem
codegen/lib/layouts/resource.tssorted properties by name alone:So a property carrying
= nullcould land ahead of a required one —AcsUserdeclared$access_schedule = nullbefore$acs_system_id. PHP deprecates that, treats the "optional" parameter as required anyway (making every default inert), and PHP 9 is expected to make it fatal.Measured on
beta:409 notices across 26 of 32 files. Zero in
src/Routes— the route generator was fixed for this in1652d01, but that commit never touched the resource generator.Nothing saw them.
psalm.xmlandphpunit.xml.distboth excludesrc/Resources, and PHPUnit routes deprecations to a channelfailOnWarningdoes not cover, so the suite stayed green through all 409.This is not only cosmetic.
composer lint:syntaxshells out tophp -l, so it fails on any host whoseerror_reportingincludesE_DEPRECATED— PHP's own default when no php.ini is loaded. It passes in CI only because the container's php.ini setsE_ALL & ~E_DEPRECATED.The fix
Emit required properties first, optional after, alphabetical within each group — the same shape
sortPhpClientMethodParametersalready produces for endpoint parameters.Deliberately not fixed by giving every parameter a default. Which properties are required is the API definition's call, carried on
isOptional; blanket-defaulting would erase that distinction to work around a code-generation ordering problem.from_jsonpasses every value by name, so it is unaffected by the reorder.Result:
Also in this PR:
failOnDeprecation="true"inphpunit.xml.dist, so this cannot come back unnoticed.isOptionalis false for many properties, and that is precisely how required parameters ended up interleaved.MIGRATION.mdentry, since positionalnew Resource(...)calls change order.Breaking change
Constructing a resource positionally binds different parameters now. Reading properties,
from_json, and named-argument construction are all unaffected.Verification
npm run generateproduces exactly the committed diff —src/Resourcesonly, nosrc/Routesdrift.failOnDeprecationon, zero deprecations.php -lclean under-d error_reporting=E_ALL.npm run lintclean,composer validate --strictclean.Note on the diff size
The bulk of the 852 deletions / 878 insertions is the per-property docblocks moving with their parameters — roughly 50 added / 50 removed per resource file. The only substantive changes are
codegen/lib/layouts/resource.ts,phpunit.xml.dist, andMIGRATION.md.One thing worth knowing if you regenerate locally:
node_modulesmust be refreshed (npm ci) after #478 landed. A stale@seamapi/typesreverts GET→POST across 19 route files, which is unrelated to this change and should not be committed.Generated by Claude Code