
Description
Hello
I realize this has been discussed before, but, after recently discussing this with a colleague, have some additional questions regarding PSR-5's stance on this. Take the following example:
/**
* @param string $bar
*/
function foo($bar) { ... }
foo(5);
In this example, I'm not passing a string as parameter. Is this in violation of the standard? Should I be explicitly casting 5
to a string? The documentation states that I should be passing a string and that is what the function's internals will be expecting, but I'm actually passing an integer. Due to PHP's type coercion, if I use the passed in number as a string in the function body, things will probably work out fine. The same applies here:
declare(strict_types=0);
/**
* @param string $bar
*/
function foo(string $bar) { ... }
foo(5); // Just fine, int will be coerced to string.
However, things are not so fine and dandy when I'm using strict typing:
declare(strict_types=1);
/**
* @param string $bar
*/
function foo(string $bar) { ... }
foo(5); // Oops!
For PHP < 7, I've always seen type declarations such as @param
as a way to strictly specify the type of a parameter in a way that wasn't possible in the language itself. Since PHP 7, we do however have scalar type hinting for this and it naturally seems to complement PSR-5.
If PSR-5 takes the stance that loose coercion is simply allowed in the cases above and the first example is correct, does this then also apply to the following case?
/**
* @param string $bar
*/
function foo($bar) { ... }
foo(null);
I did not indicate that $bar
is nullable, but null
coerces to a string
in the sense that you can use it in situations where strings are expected (such as concatenations), so is the string|null
indication now obsolete? One could argue that no, that is not the case, since with PHP 7 that is also not the case:
/**
* @param string $bar
*/
function foo(string $bar) { ... }
foo(null); // Error in both strict and non-strict mode.
So this makes me think that docblocks should be strict about the type and explicitly state the types they allow, in this case string|null
. But now we are in violation of our first conclusion: we were passing an int
that loosely coerces to a string, which is wrong, since int
is not an explicitly allowed type in our docblock, i.e. it says string|null
, not string|int|null
or even mixed
.
This brings me to the final question: how strict are docblocks regarding typing? Are they interpreted in the same way in strict (PHP 7) and non-strict typing mode? If not, will we have to update all our docblocks if we transition from one mode to another in a file? Do they perhaps follow the strict typing mode of the file?
The most important reason for asking this question is with regards to tools and IDE's: If we leave this open for interpretation by tools doing static analysis for types, we will get varying results between them, and if we get varying results and the types are still open to interpretation, what good is specifying them at all?