Assertion syntax

Psalm’s assertion annotation supports a number of different assertions.

Psalm assertions are of the form

@psalm-assert(-if-true|-if-false)? (Assertion) (Variable or Property)

Assertion here can have many forms:

Regular assertions

is_xxx assertions

Most is_xxx PHP functions have companion assertions e.g. int for is_int. Here's the full list:

  • int
  • float
  • string
  • bool
  • scalar
  • callable
  • countable
  • array
  • iterable
  • numeric
  • resource
  • object
  • null

So a custom version is_int could be annotated in Psalm as

<?php
/** @psalm-assert-if-true int $x */
function custom_is_int($x) {
  return is_int($x);
}

Object type assertions

Any class can be used as an assertion e.g.

@psalm-assert SomeObjectType $foo

Generic assertions

Generic type parameters can also now be asserted e.g.

@psalm-assert array<int, string> $foo

Negated assertions

Any assertion above can be negated:

This asserts that $foo is not an int:

<?php
/** @psalm-assert !int $foo */

This asserts that $bar is not an object of type SomeObjectType:

<?php
/** @psalm-assert !SomeObjectType $bar  */

Bool assertions

This asserts that $bar is true:

<?php
/** @psalm-assert true $bar  */

This asserts that $bar is not false:

<?php
/** @psalm-assert !false $bar  */

Equality assertions

Psalm also supports the equivalent of assert($some_int === $other_int) in the form

<?php
/** @psalm-assert =int $some_int */

There are two differences between the above assertion and

<?php
/** @psalm-assert int $some_int */

Firstly, the negation of =int has no meaning:

<?php
/** @psalm-assert-if-true =int $x */
function equalsFive($x) {
  return is_int($x) && $x === 5;
}

function foo($y) : void {
  if (equalsFive($y)) {
    // $y is definitely an int
  } else {
    // $y might be an int, but it might not
  }
}

function bar($y) : void {
  if (is_int($y)) {
    // $y is definitely an int
  } else {
    // $y is definitely not an int
  }
}

Secondly, calling equalsFive($some_int) is not a RedundantCondition in Psalm, whereas calling is_int($some_int) is.