Trinary Logic

Many methods in PHPStan do not return a two-state boolean, but a three-state PHPStan\TrinaryLogic object.

The object can be created by calling one of the static methods:

  • PHPStan\TrinaryLogic::createYes(): self
  • PHPStan\TrinaryLogic::createMaybe(): self
  • PHPStan\TrinaryLogic::createNo(): self
  • PHPStan\TrinaryLogic::createFromBoolean(bool $value): self

You can ask what value the object represents by calling one of these instance methods:

  • PHPStan\TrinaryLogic::yes(): bool
  • PHPStan\TrinaryLogic::maybe(): bool
  • PHPStan\TrinaryLogic::no(): bool
  • PHPStan\TrinaryLogic::no(self $other): bool

The object is immutable. You can combine multiple instances either with AND or OR logical operations. These methods return new instances:

  • PHPStan\TrinaryLogic::and(self ...$operands): self
  • PHPStan\TrinaryLogic::or(self ...$operands): self

Usage in practice #

PHPStan uses trinary logic in many places, especially on the PHPStan\Type\Type interface (see the article about the type system).

For example, let’s say we have a new ObjectType(\Exception::class) and we ask about hasMethod('getMessage'). This method will return TrinaryLogic’s yes because the method always exists.

If we have Exception|stdClass union, hasMethod('getMessage') returns maybe, because the method is available only on one of the subtypes.

Asking new ObjectType(\Exception::class) whether it hasMethod('doFoo') returns no, because that method does not exist on Exception.

Trinary logic is at the core of PHPStan’s rule levels. Up until level 6, most rules ask whether the result is !no(), meaning that yes and maybe are valid answers and no error is reported in that case. On level 7 and up, yes() is required, meaning that only yes is a valid answer.

Edit this page on GitHub

© 2016–2021 Ondřej Mirtes