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

Specify detailed return type of parse() #79

Merged
merged 3 commits into from
Aug 30, 2022

Conversation

phil-davis
Copy link
Contributor

If I increase phpstan level to 9, then it detects that function parse(string $uri): array can return array<string, int|string|null> and that is correct.

Key "port" is an int value. Other keys have a string value. "Unused" keys have value null.

If I actually document:

 * @return array<string, int|string|null>

Then phpstan complains about:

------ ------------------------------------------------------------------------------------------------- 
  Line   lib/functions.php                                                                                
 ------ ------------------------------------------------------------------------------------------------- 
  60     Parameter #1 $string of function substr expects string, int|string|null given.                   
  68     Parameter #2 $str of function explode expects string, int<min, -1>|int<1, max>|string given.     
  117    Parameter #1 $str of function ltrim expects string, int<min, -1>|int<1, max>|string given.       
  138    Parameter #1 $str of function strtolower expects string, int<min, -1>|int<1, max>|string given.  
  161    Parameter #1 $str of function strtolower expects string, int<min, -1>|int<1, max>|string given.  
 ------ ------------------------------------------------------------------------------------------------- 

because it has not been told the detail that:
Key "port" can have value int|null
All other keys have value string|null

If there is some way to express this in PHPdoc, then that would be good - because the line numbers above are processing keys that do not have int value.

For now, I set the type of the keys to mixed - at least that recognizes that the values are definitely not all string.

@phil-davis phil-davis requested a review from staabm August 30, 2022 09:13
@phil-davis phil-davis self-assigned this Aug 30, 2022
@codecov
Copy link

codecov bot commented Aug 30, 2022

Codecov Report

Merging #79 (602106d) into master (4df7398) will not change coverage.
The diff coverage is 100.00%.

@@           Coverage Diff           @@
##           master      #79   +/-   ##
=======================================
  Coverage   98.54%   98.54%           
=======================================
  Files           1        1           
  Lines         137      137           
=======================================
  Hits          135      135           
  Misses          2        2           
Impacted Files Coverage Δ
lib/functions.php 98.54% <100.00%> (ø)

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@phil-davis
Copy link
Contributor Author

Note: if I go up to phpstan level 9, then it does not like me just using mixed. but it also seems to not have a way for me to express the full detail of the values that can be int|string|null. So I get a bit stuck - phpstan insists on telling me the 5 things in the top post. To shut it up, I would have to add (string) casts in those places, even though I am confident that the values are already string.

lib/functions.php Outdated Show resolved Hide resolved
@staabm
Copy link
Member

staabm commented Aug 30, 2022

Level9 is very brutal. It does not allow mixed.

Most of the time this means you need a lot of typing and/or ignores

@phil-davis phil-davis requested a review from staabm August 30, 2022 09:49
lib/functions.php Outdated Show resolved Hide resolved
Comment on lines -57 to 60
$path = $base['path'];
$length = strrpos((string) $path, '/');
$path = (string) $base['path'];
$length = strrpos($path, '/');
if (false !== $length) {
$path = substr($path, 0, $length);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the detailed types, and level 9, phpstan found this.
To be really safe, we cast $path to a string straight away. Then its use at line 60 - passing to substr() is also safe.

@phil-davis phil-davis changed the title Broaden return type of parse() Specify detailed return type of parse() Aug 30, 2022
@phil-davis phil-davis requested a review from staabm August 30, 2022 09:55
* above the function call.
*
* @phpstan-ignore-next-line
*/
return
$result + [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess my recent fix regarding + will resolve this phpstan error on the next release

phpstan/phpstan-src#1579

@phil-davis phil-davis merged commit ac6f665 into sabre-io:master Aug 30, 2022
@phil-davis phil-davis deleted the broaden-return-type-of-parse branch August 30, 2022 10:07
@phil-davis
Copy link
Contributor Author

If the type can be expressed in detail, then phpstan at a high level seems good at finding places where something is used in the wrong way. It takes effort to specify everything, but in the end it seems a good way to avoid dumb-type-errors and regressions.

@phil-davis
Copy link
Contributor Author

I will make a patch release to get this published, so that other repos that pull in sabre/uri as a dependency will get the updated type information and code...

@staabm
Copy link
Member

staabm commented Aug 30, 2022

👍

thx for doing all this.. library users will benefit a lot from it

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.

2 participants