never, void, and static
Some return types aren't about values at all. They're about what happens next: whether the method comes back, whether its result means anything, and what kind of object you get to carry on with. Get them wrong and PHPStan reasons about code paths that can't happen, and misses ones that can.
never: this doesn't come back
A guard helper that always throws is common and useful:
Guard::fail("Unknown warehouse $code");
Declare it void and PHPStan has to assume it returns. Every caller then seems to fall off the end of the method without returning a value. never says the function can't finish normally: it always throws or exits. PHPStan then knows that nothing after the call runs.
void: don't use my result
void doesn't just mean "returns nothing". It's a promise to callers that there's nothing worth looking at. PHPStan reports any caller that uses the result of a void method, and from level 4 it adds that an if around one is always false.
If callers need to know what happened, the method isn't void. Give it an honest return type, like bool for "did anything change?", rather than having callers check state afterwards.
static: the class you called it on
Fluent methods usually return $this. Declared as self, the return type means the class this method is written in, even when it's called on a subclass:
(new OrderEmail())->to('sam@example.test')->withTracking(); // Call to an undefined method Email::withTracking().
PHP runs this fine, because $this really is an OrderEmail. But the signature says Email, so PHPStan only believes Email. static means "the class this was called on", which is what return $this actually returns.
Power-up
<?php final class Guard { public static function fail(string $message): void { throw new LogicException($message); } } class Email { public function to(string $address): self { $this->to[] = $address; return $this; } }
<?php final class Guard { public static function fail(string $message): never { throw new LogicException($message); } } class Email { public function to(string $address): static { $this->to[] = $address; return $this; } }