Do you have a big project where you try to raise the PHPStan level as high as possible? Yet, you're stuck on level 4 or 5 with thousands of errors? We all have one and try to chip away a few errors now and then.
The mixed
type is the worst of all of them. Fixing all mixed
types to a specific type is a nightmare for the REST of your life (pun intended). But what if there are places where fixing mixed
type brings much more value than in the others?
We're in a state where code runs, tests pass, and everything works. We can find snippets like this one:
function printNames(array $names)
{
foreach ($names as $name)
{
echo $name;
}
}
We know that the $names
parameter is mixed[]
type. It is probably a string[]
, int[]
or StringableInterface
type. We could run the code, write the test, detect the type and complete it.
But by adding a specific type here, we will not get much new information. The value will still be echo-able, and the code will still work. We will have one less ignored error in phpstan.neon
.
Maybe my boss would let me remove all the mixed
types from the project, but it would make their expenses high enough to fire me. The coding must be economical and beneficial for the project's future.
Instead of looking for the origin of mixed
with the attention of detective Colombo, we could do something better with our time. We could find those mixed
type that is now blocking PHPStan from further analysis. We do not have to test manually a mixed
type and hope for the user input.
In the same project, we find the following code:
function printNames(array $videos)
{
foreach ($videos as $video)
{
echo $this->renderUrl($video->getUrl());
}
}
From the PHPStan point of view, this snippet is identical to the previous one. There is a variable $videos
with mixed[]
type. PHPStan can't analyze the mixed
type, as it can be anything from scalar, null
, false
, object, collection of objects and nested array of all above, etc.
What can we assume from this code?
$video->getUrl()
$video
is an object$video
object has a getUrl()
methodHow can we deduct the type of object here?
Here you could read a complex passage about types, abstract syntax tree, static analysis, etc.
Instead, we'll be KISSing PHPStorm:
We see the responsible type is Video
object, and we can complete it to our code:
+/**
+ * @param Video[] $videos
+ */
function printNames(array $videos)
{
foreach ($videos as $video)
{
echo $this->renderUrl($video->getUrl());
}
}
Thanks to this type the PHPStan now can analyze if:
getUrl()
are valid (if any provided)$this->renderUrl()
param type is compatible with getUrl()
return type✅
That's how we can use a method call on mixed
to our advantage.
mixed
" > any mixed
The second use case for object mixed
is similar. You can probably already guess it:
function collectIds(array $videos): array
{
$ids = [];
foreach ($videos as $video)
{
$ids[] = $video->id;
}
return $ids;
}
Yes, it's property fetch. We can fetch property only on a specific object. Well, except stdClass
that is typical for json_decode()
return values. But apart from that, property fetch is a sure sign of a known object.
Again, we'll be KISSing PHPStorm:
And complete the types based on found Video
object:
+/**
+ * @param Video[] $video
+ * @return int[]
+ */
function collectIds(array $videos): array
{
$ids = [];
foreach ($videos as $video)
{
$ids[] = $video->id;
}
return $ids;
}
Our code is now slightly more intelligent, and PHPStan now sees:
$video
has property $id
@var
/strict type of $id
property✅
mixed
with PHPStan?We can teach PHPStan to report these low-hanging fruit cases. The conditions are straightforward:
Variable
(no magic)mixed
// method call → MethodCall node
$video->getUrl();
$video->id;
// property fetch → PropertyFetch node
You'd be surprised if you'd have to write those rules on your own.
They're freshly included in symplify/phpstan-rules ↓
How did the rule perform on Symplify itself? The property rule passed without any report, but the method called one found over 20 cases of unknown type. Despite the fact we have PHPStan on level 8. Pretty neat, right?
How many object
mixed types do you have? Register rules and let PHPStan disclose the magic:
# phpstan.neon
rules:
- Symplify\PHPStanRules\Rules\Explicit\NoMixedPropertyFetcherRule
- Symplify\PHPStanRules\Rules\Explicit\NoMixedMethodCallerRule
Happy coding!
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors.
I'd really appreciate it!