Accept decimal-int-string arguments for %d printf placeholders in strict mode - #5997
Merged
staabm merged 1 commit intoJul 5, 2026
Merged
Conversation
VincentLanglet
approved these changes
Jul 4, 2026
…ict mode
- PrintfPlaceholder::doesArgumentTypeMatchPlaceholder() now accepts a
`decimal-int-string` (string&AccessoryDecimalIntegerStringType) for the
`int` acceptingType when strict placeholder type checks are enabled, in
addition to plain `int`. Such strings ("42", "-1", "0") are printed by %d
without any lossy conversion.
- numeric-string and non-decimal-int-string ("00", "+1", "1.23") are still
rejected because %d would trim/alter their value.
- Left the stricter `strict-int` acceptingType (width/precision, %*d) and the
`float`/`string`/`mixed` cases unchanged: %f already allows numeric-string
(a superset of decimal-int-string), and width/precision remain int-only by
design.
staabm
force-pushed
the
create-pull-request/patch-n6g171s
branch
from
July 5, 2026 09:42
c89dcf5 to
637cb1d
Compare
staabm
approved these changes
Jul 5, 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.
Summary
In strict printf placeholder mode (
checkStrictPrintfPlaceholderTypes), passing an integer-valued string such as'42'to a%dplaceholder was reported as an error. As discussed in the issue, adecimal-int-stringis printed by%dwithout any lossy conversion, so it should be accepted. This change allowsdecimal-int-stringfor%d-family placeholders while continuing to rejectnumeric-stringand other strings that%dwould trim or alter.Changes
src/Rules/Functions/PrintfPlaceholder.php: for theintaccepting type in strict mode, acceptintordecimal-int-string(string & AccessoryDecimalIntegerStringType) instead of onlyint. Mirrors how thefloatcase already acceptsnumeric-string.tests/PHPStan/Rules/Functions/data/printf-param-types.phpandPrintfParameterTypeRuleTest.php: added regression cases fordecimal-int-string(OK),numeric-string(error),non-decimal-int-string(error), and constant strings'42'/'-1'/'0'(OK) vs'00'/'+1'(error).Root cause
The strict
intbranch checked only(new IntegerType())->accepts($argumentType, true)->yes(), which rejects any string type.%dcasts its argument to an integer; for adecimal-int-stringthis cast is lossless (the string already is the canonical decimal representation of an integer), so there is no reason to report it. The fix reuses the existingAccessoryDecimalIntegerStringTypeaccessory type — the same abstraction PHPStan uses to decide whether a string array key is cast to int.Analogous cases probed:
float(%f,%e,%g, …): already acceptsnumeric-string, which is a superset ofdecimal-int-string, so it was already correct — no change needed.strict-int(width/precision, e.g.%*d): intentionally kept int-only; these are a deliberately stricter category and the reported issue concerns only the%dvalue slot.'42','-1','0'are recognized asdecimal-int-stringbyConstantStringType::isDecimalIntegerString(), so they are now accepted too (covering theprintf('%d', '42')example from the discussion), while'00'/'+1'/'1.23'remain errors.Test
PrintfParameterTypeRuleTest::testStrictgains cases asserting thatdecimal-int-stringand constant int-strings are accepted for%d, whilenumeric-string,non-decimal-int-string, and non-canonical constant strings still produce errors. The non-stricttestcontinues to pass unchanged. The regression fails without the source change (thedecimal-int-stringcase is reported as an unexpected error).Fixes phpstan/phpstan#13609