Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Casting preg_match() return value breaks array shapes for $matches by-ref parameter #11262

Closed
westonruter opened this issue Jul 1, 2024 · 18 comments
Labels
Milestone

Comments

@westonruter
Copy link
Contributor

Bug report

I just noticed that phpstan/phpstan-src#2589 doesn't seem to play well with strict rules.

This example without strict rules works: https://phpstan.org/r/6187bcca-8fc8-459b-9790-21a82e62b345

But when I enable strict rules, I need to cast the return value of preg_match() to a bool and this seems to block the types from passing through. For example: https://phpstan.org/r/f368fc07-6438-43f1-b80b-93dee22535f4

Same thing happens when I cast to an int: https://phpstan.org/r/0d011355-4446-4bd8-9b8d-0c44907f9a07

Code snippet that reproduces the problem

https://phpstan.org/r/f368fc07-6438-43f1-b80b-93dee22535f4

Expected output

No issue should have been detected

Did PHPStan help you today? Did it make you happy in any way?

No response

@mvorisek
Copy link
Contributor

mvorisek commented Jul 1, 2024

related with phpstan/phpstan-src#3175, IMO such hack should not be needed as the return type is always 1|false and thus == 1 is strictly equal to === 1

@ondrejmirtes
Copy link
Member

phpstan-strict-rules doesn't require you to cast to bool. You can do this instead: https://phpstan.org/r/7b3e4faf-28d9-426f-96de-42a65f2a8416 (typo on purpose to verify the inference works)

But otherwise yeah, this is a bug worth fixing.

@westonruter westonruter changed the title Casting preg_match() return value to bool breaks array shapes for $matches by-ref parameter Casting preg_match() return value breaks array shapes for $matches by-ref parameter Jul 1, 2024
@staabm
Copy link
Contributor

staabm commented Jul 2, 2024

@staabm
Copy link
Contributor

staabm commented Jul 2, 2024

related with phpstan/phpstan-src#3175, IMO such hack should not be needed as the return type is always 1|false and thus == 1 is strictly equal to === 1

@mvorisek preg_match returns 1|0|false .. I don't think its as easy implemented as you think.

but maybe you want to give it a try and see how it goes

@mvorisek
Copy link
Contributor

mvorisek commented Jul 2, 2024

I mean "truthy context" should be implied also by expr == 1 or (bool) expr.

@ondrejmirtes ondrejmirtes added this to the Easy fixes milestone Jul 6, 2024
@phpstan-bot
Copy link
Contributor

@westonruter After the latest push in 1.12.x, PHPStan now reports different result with your code snippet:

@@ @@
-17: Offset 'background_image' might not exist on array{0?: string, background_image?: string, 1?: string}.
+No errors

@phpstan-bot
Copy link
Contributor

@westonruter After the latest push in 1.12.x, PHPStan now reports different result with your code snippet:

@@ @@
-17: Offset 'background_image' might not exist on array{0?: string, background_image?: string, 1?: string}.
+No errors

@phpstan-bot
Copy link
Contributor

@ondrejmirtes After the latest push in 1.12.x, PHPStan now reports different result with your code snippet:

@@ @@
-17: Offset 'background_imagee' does not exist on array{0: string, background_image: string, 1: string}.
+No errors

@phpstan phpstan deleted a comment from phpstan-bot Jul 19, 2024
@phpstan phpstan deleted a comment from phpstan-bot Jul 19, 2024
@phpstan phpstan deleted a comment from phpstan-bot Jul 19, 2024
@phpstan-bot
Copy link
Contributor

@westonruter After the latest push in 1.12.x, PHPStan now reports different result with your code snippet:

@@ @@
-17: Offset 'background_image' might not exist on array{0?: string, background_image?: string, 1?: string}.
+17: Offset 'background_image' might not exist on array{0?: string, background_image?: non-empty-string, 1?: non-empty-string}.
Full report
Line Error
17 Offset 'background_image' might not exist on array{0?: string, background_image?: non-empty-string, 1?: non-empty-string}.

@phpstan-bot
Copy link
Contributor

@westonruter After the latest push in 1.12.x, PHPStan now reports different result with your code snippet:

@@ @@
-17: Offset 'background_image' might not exist on array{0?: string, background_image?: string, 1?: string}.
+17: Offset 'background_image' might not exist on array{0?: string, background_image?: non-empty-string, 1?: non-empty-string}.
Full report
Line Error
17 Offset 'background_image' might not exist on array{0?: string, background_image?: non-empty-string, 1?: non-empty-string}.

@phpstan-bot
Copy link
Contributor

@ondrejmirtes After the latest push in 1.12.x, PHPStan now reports different result with your code snippet:

@@ @@
-17: Offset 'background_imagee' does not exist on array{0: string, background_image: string, 1: string}.
+17: Offset 'background_imagee' does not exist on array{0: string, background_image: non-empty-string, 1: non-empty-string}.
Full report
Line Error
17 Offset 'background_imagee' does not exist on array{0: string, background_image: non-empty-string, 1: non-empty-string}.

@westonruter
Copy link
Contributor Author

Fixed as of v1.11.8

@Seldaek
Copy link
Contributor

Seldaek commented Jul 24, 2024

Are you sure? I can still repro your error from first post, and as far as I know this issue was not addressed

@westonruter
Copy link
Contributor Author

westonruter commented Jul 24, 2024

In my PHP code I was needing to add this condition '' !== $matches['background_image'] as in the following if statement:

if (
	is_string( $style )
	&&
	1 === preg_match( '/background(?:-image)?\s*:[^;]*?url\(\s*[\'"]?\s*(?<background_image>.+?)\s*[\'"]?\s*\)/', $style, $matches )
	&&
	'' !== $matches['background_image'] // PHPStan should ideally know that this is a non-empty string based on the `.+?` regular expression. See <https://github.com/phpstan/phpstan/issues/11222>.
	&&
	! $this->is_data_url( $matches['background_image'] )
) {

No longer needed as of the latest version: WordPress/performance#1395

@westonruter
Copy link
Contributor Author

Ah wait, it's working because I changed it to check the return value of preg_match() to be equal to 1. It is still broken if I try (bool) preg_match(...).

@westonruter westonruter reopened this Jul 24, 2024
@phpstan-bot
Copy link
Contributor

@staabm After the latest push in 1.12.x, PHPStan now reports different result with your code snippet:

@@ @@
-6: Expected type non-empty-array, actual: array
+No errors

@staabm
Copy link
Contributor

staabm commented Sep 3, 2024

@ondrejmirtes the repro-snippet of this issue was fixed with the recent cast-narrowing improvements (see phpstan-bot comment above).

I have copied the only left repro from the description into #11293, as it is very similar to the mentioned referenced issue.

this means we can close here IMO.

Copy link

github-actions bot commented Oct 7, 2024

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants