Skip to content

Specify detailed return type of parse()#79

Merged
phil-davis merged 3 commits into
sabre-io:masterfrom
phil-davis:broaden-return-type-of-parse
Aug 30, 2022
Merged

Specify detailed return type of parse()#79
phil-davis merged 3 commits into
sabre-io:masterfrom
phil-davis:broaden-return-type-of-parse

Conversation

@phil-davis
Copy link
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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.

Comment thread lib/functions.php Outdated
@staabm
Copy link
Copy Markdown
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
Comment thread lib/functions.php Outdated
Comment thread lib/functions.php
Comment on lines 57 to 60
// Removing last component from base path.
$path = $base['path'];
$length = strrpos((string) $path, '/');
$path = (string) $base['path'];
$length = strrpos($path, '/');
if (false !== $length) {
$path = substr($path, 0, $length);
Copy link
Copy Markdown
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
Comment thread lib/functions.php
* @phpstan-ignore-next-line
*/
return
$result + [
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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