But ever since, I've been quietly noticing "Psalm errors," where the phpdoc doesn't match types in practice, or doesn't match the actual type declarations on the method.
(Of course, my API design has been strongly affected by PHP type declaration syntax; I am now trying to design "less convenient" interfaces that offer stronger type information for the IDE. I can't declare
string|array|falsein PHP, but I can declare
?arrayfor an array or null. This just happens to align with reducing the amount of options Psalm has to deal with.)
Added 2022-01-26: This is not true anymore; PHP 8.0 introduced unions in type declarations. However, if a function returns
string|array|false, but exactly which one depends on one of the arguments, Psalm still wants the caller to handle every possibility. I still find it more ergonomic to try to limit the interface to
?arrayand keep things simple. The other false aspect is that I decided to use Psalm where I get the most value from it. It is in use with some core API code, and all new sub-projects I have started. It's so much easier to keep everything clean from the start, than it is to clean up later.