An analyser rule for hooks that reach outside the object

A convention that had been enforced by review, expressed as a rule after review failed twice.

final class HookPurityRule implements Rule
{
    public function processNode(Node $node, Scope $scope): array
    {
        if (! $this->isInsideAGetHook($node, $scope)) {
            return [];
        }

        // any method call on anything other than $this
        return $this->isCallOnAnotherObject($node)
            ? [RuleErrorBuilder::message(
                'a get hook must not call another object',
              )->build()]
            : [];
    }
}

The rule is crude — it forbids calling anything on a collaborator, which catches the query case and also catches a legitimate call to a value object’s method. Twelve exceptions were needed and all twelve are on value objects, which suggests a better rule exists and this one is what I could write in an afternoon.