Description
I do not believe that the coding standard should enforce the usage of union types over the nullable ones. From the original discussion in doctrine/orm#9886 (comment):
Personally, I believe arbitrary union types (e.g.
getValue(sting $key): int|string|false
) often reflect poor API design while nullable types are fine (e.g.findUser(int $id): ?User
).I think that enforcing a feature introduced primarily to support the existing poor design of the PHP's own API and the type system as a one-size-fits-all solution is not the right move.
[...]
IMO, union types are often poor because they make the consumer deal with a set of types instead of one by adding conditionals. Without pattern matching, it's error-prone since there's no guarantee that every consumer will handle each type from the union.
Specifically, in the PHP's standard library, union types go hand in hand with the APIs that are known as extremely error-prone, e.g.
if (strpos($str, substr)) ...
) orwhile ($value = $stmt->fetch(PDO::FETCH_COLUMN)) ...
. Union types are also needed to deal with array keys because there's no built-in support for maps in PHP and numeric array keys are converted to strings.All the
int|string
types used in the code that fetches data from the database are because there's no support for unsigned integers and decimals in PHP. Otherwise, it would be possible to implement an API that returns a specific type.Looking at the DBAL code, the only place I see where a union type is used deliberately is the expression builder where the methods accept strings or expressions but even there they could be split into two: one for stings, the other for expressions.