Skip to content

Give password_get_info() the array shape it always returns - #6299

Open
SanderMuller wants to merge 1 commit into
phpstan:2.2.xfrom
SanderMuller:password-get-info-shape
Open

Give password_get_info() the array shape it always returns#6299
SanderMuller wants to merge 1 commit into
phpstan:2.2.xfrom
SanderMuller:password-get-info-shape

Conversation

@SanderMuller

Copy link
Copy Markdown
Contributor

password_get_info() returns a bare array, so $info['algo'] is mixed and a mistyped key is never reported. The shape is fixed and documented, and algo changed from int to string|null in PHP 8.0.

Measured on both targets, before and after:

phpVersion before after
70400 array, $info['algo'] is mixed array{algo: int, algoName: string, options: array<string, mixed>}, $info['algo'] is int
80300 array, $info['algo'] is mixed array{algo: string|null, algoName: string, options: array<string, mixed>}, $info['algo'] is string|null

The keys match the #[ArrayShape] on password_get_info() in the vendored phpstorm-stubs, which annotates algo as int and has not been updated for the 8.0 change. The string|null half is from running PHP 8: a bcrypt hash gives '2y' and plain text gives null.

The baseline map carries the pre-8.0 signature and the 8.0 delta carries the newer one, matching password_hash() on the line below it, since the deltas apply forward from the oldest map.

This also removes a false negative rather than only sharpening a type. if (!$info['algo']) is currently a condition on mixed, which phpstan-strict-rules passes through its implicit-mixed branch and never reports. With the shape it is a condition on string|null, which is what that rule exists to catch. I found it that way round: an analyser without this gap reported the condition and PHPStan did not.

It returned a bare array, so $info['algo'] was mixed and a key typo went
unreported. The shape is fixed and documented: algo, algoName and options,
with algo changing from int to string|null in PHP 8.0.

Measured on the two targets, before and after:

  phpVersion 70400   array                  -> array{algo: int, ...}
                     $info['algo'] mixed    -> int
  phpVersion 80300   array                  -> array{algo: string|null, ...}
                     $info['algo'] mixed    -> string|null

The baseline entry carries the pre-8.0 signature and the 8.0 delta carries
the newer one, matching password_hash() directly above it, since the deltas
apply forward from the oldest map.

This removes a false negative rather than only sharpening a type. In real code
"if (!$info['algo'])" is a condition on mixed, which phpstan-strict-rules
passes through its implicit-mixed branch and never reports. With the shape it
is a condition on string|null and gets reported, which is what the rule is for.
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