Typing in Psalm

Psalm is able to interpret all PHPDoc type annotations, and use them to further understand the codebase.

Types are used to describe acceptable values for properties, variables, function parameters and return $x.

Docblock Type Syntax

Psalm allows you to express a lot of complicated type information. See this guide for a detailed list of supported types.

Property declaration types vs Assignment typehints

You can use the /** @var Type */ docblock to annotate both property declarations and to help Psalm understand variable assignment.

Property declaration types

You can specify a particular type for a class property declarion in Psalm by using the @var declaration:

/** @var string|null */
public $foo;

When checking $this->foo = $some_variable;, Psalm will check to see whether $some_variable is either string or null and, if neither, emit an issue.

If you leave off the property type docblock, Psalm will emit a MissingPropertyType issue.

Assignment typehints

Consider the following code:

namespace YourCode {
  function bar() : int {
    $a = \ThirdParty\foo();
    return $a;
  }
}
namespace ThirdParty {
  function foo() {
    return mt_rand(0, 100);
  }
}

Psalm does not know what the third-party function ThirdParty\foo returns, because the author has not added any return types. If you know that the function returns a given value you can use an assignment typehint like so:

namespace YourCode {
  function bar() : int {
    /** @var int */
    $a = \ThirdParty\foo();
    return $a;
  }
}
namespace ThirdParty {
  function foo() {
    return mt_rand(0, 100);
  }
}

This tells Psalm that int is a possible type for $a, and allows it to infer that return $a; produces an integer.

Unlike property types, however, assignment typehints are not binding – they can be overridden by a new assignment without Psalm emitting an issue e.g.

/** @var string|null */
$a = foo();
$a = 6; // $a is now typed as an int

You can also use typehints on specific variables e.g.

/** @var string $a */
echo strpos($a, 'hello');

This tells Psalm to assume that $a is a string (though it will still throw an error if $a is undefined).

Specifying string/int options (aka enums)

Psalm allows you to specify a specific set of allowed string/int values for a given function or method.

Whereas this would cause Psalm to complain that not all paths return a value:

function foo(string $s) : string {
  switch ($s) {
    case 'a':
      return 'hello';

    case 'b':
      return 'goodbye';
  }
}

If you specify the param type of $s as 'a'|'b' Psalm will know that all paths return a value:

/**
 * @param 'a'|'b' $s
 */
function foo(string $s) : string {
  switch ($s) {
    case 'a':
      return 'hello';

    case 'b':
      return 'goodbye';
  }
}

If the values are in class constants, you can use those too:

class A {
  const FOO = 'foo';
  const BAR = 'bar';
}

/**
 * @param A::FOO | A::BAR $s
 */
function foo(string $s) : string {
  switch ($s) {
    case A::FOO:
      return 'hello';

    case A::BAR:
      return 'goodbye';
  }
}