psalm: Mechanisms for not 'trusting' docblock types
This spins out from #8005 and some slack conversations
In general Psalm treats docblock types as truth. This is great for an application because I can add @param array<Foo>
, no longer feel like I have to validate my array, and any calling code that doesn’t obey the type definition is caught.
For libraries this is different - specific APIs are going to be accessed by code that may not be validated using Psalm (or other SA). This leaves the author with choices
- Decide that callers who ignore the type are ‘wrong’ and any errors are part of ‘undefined behaviour’ and their own fault
- Write redundant checking code that Psalm will complain is unnecessary
- De-activate the param somehow (e.g.
@var mixed
inside the body of the function) - Lose your mind like @Ocramius and write a library to make everyone use psalm
IMO we should have a way to opt out of this behaviour either globally, per method, or using an internal/external mechanism:
Global opt-out
Any validated callers would still need to pass the right types, but when evaluating the code inside the function the docblock param would effectively be ignored
<psalm
useDocblockParamTypesInFunctionBody="false"
/>
/** @param non-empty-array<Foo> $a */
function f(array $a): Foo
{
return current($a); // MixedReturnStatement here
}
f([]); // still an InvalidArgument here
Per-functions opt-out
It may be we only want to do this for certain functions that we ‘know’ are going to be called from an untrusted source. In that case a flag in the docblock would make sense:
/**
* @param non-empty-array<Foo> $a
* @psalm-ignore-docblock-params
*/
function f(array $a): Foo
{
return current($a); // MixedReturnStatement here
}
‘External’ opt-out
Many libraries have an existing concept of what is internal or external to them. We could have a setting that uses that existing labelling
<psalm
useDocblockParamTypesInExternalFunctionBody="false"
/>
/**
* @param non-empty-array<Foo> $a
*/
function f(array $a): Foo
{
return current($a); // MixedReturnStatement
}
/**
* @param non-empty-array<Foo> $a
* @internal
*/
function g(array $a): Foo
{
return current($a); // no error here because we assume all callers are validated
}
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 3
- Comments: 19 (9 by maintainers)
Commits related to this issue
- Add docblock tag to require functions to validate param types (fixes #8017). — committed to AndrolGenhald/psalm by AndrolGenhald 2 years ago
🤣
Thanks for writing this up as a clear feature request.