@param int|string $id. I grepped one service this morning: dozens of those, and every one is a wish. The docblock says what the signature could not. First alpha of PHP 8 came out last week, and native union types turn the wish into a contract, checked at runtime and by tooling. Half of my phpdoc can go.
Everyone writes about the JIT. I keep thinking about the less shiny thing: how many of our daily patterns exist only to compensate for a missing language feature, and are about to become legacy.
Annotations in docblocks are the big one. Fifteen years we put machine-readable metadata into comments, wrote parsers for the comments, and called it normal. Doctrine mappings, route definitions, whole frameworks configured through strings the engine never sees. Attributes make metadata part of the language. Typos become errors, IDEs and static analyzers finally see it. I will not show the syntax here. They changed it once already during the RFC, and I would not bet against a second time. The idea is what matters.
Named arguments are still argued about on internals, but it looks likely. If it lands, the options array dies: doSomething(['force' => true, 'dryRun' => false]) becomes real parameters with real types. One catch. Parameter names become public API. Rename $dryRun to $dry in a library and you break callers. Library authors will have to think about names the way they think about method names now.
None of this makes old code wrong. But when the language absorbs a workaround, the workaround starts to read as noise.
I wrote one of those docblock parsers myself, years ago. It is still running somewhere. I hope nobody opens it.