PSR-2 predated return types, nullable types, multi-line arguments and trait conflict resolution, so every project had a house rule for each of them. PSR-12 writes them down.
declare(strict_types=1);
namespace AppBilling;
use AppMoney;
final class Invoice implements Renderable, JsonSerializable
{
public function total(
Money $net,
?TaxRate $rate = null
): Money {
// note: the brace on the same line as the closing paren
}
}
The rules that actually change a codebase are the multi-line signature form and the ordering of declare, namespace and use. Everything else is a clarification. phpcbf applies almost all of it automatically, so the migration is one commit and a note in the review guidelines — and doing it as its own commit rather than mixed with logic is what keeps the next month’s git blame usable.