Psalm supports a wide range of docblock annotations.
Psalm uses the following PHPDoc tags to understand your code:
@var
Used for specifying the types of properties and variables@return
Used for specifying the return types of functions, methods and closures@param
Used for specifying types of parameters passed to functions, methods and closures@property
Used to specify what properties can be accessed on an object that uses__get
and__set
@property-read
Used to specify what properties can be read on object that uses__get
@property-write
Used to specify what properties can be written on object that uses__set
@deprecated
Used to mark functions, methods, classes and interfaces as being deprecated@internal
used to mark classes, functions and properties that are internal to an application or library.
The @var
tag is supposed to only be used for properties. Psalm, taking a lead from PHPStorm and other static analysis tools, allows its use inline in the form @var Type [VariableReference]
.
If VariableReference
is provided, it should be of the form $variable
or $variable->property
. If used above an assignment, Psalm checks whether the VariableReference
matches the variable being assigned. If they differ, Psalm will assign the Type
to VariableReference
and use it in the expression below.
If no VariableReference
is given, the annotation tells Psalm that the right hand side of the expression, whether an assignment or a return, is of type Type
.
/** @var string */
$a = $_GET['foo'];
/** @var string $b */
$b = $_GET['bar'];
function bat(): string {
/** @var string */
return $_GET['bat'];
}
There are a number of custom tags that determine how Psalm treats your code.
This is used to specify that a by-ref type is different from the one that entered. In the function below the first param can be null, but once the function has executed the by-ref value is not null.
/**
* @param-out string $s
*/
function addFoo(?string &$s) : void {
if ($s === null) {
$s = "hello";
}
$s .= "foo";
}
When specifying types in a format not supported by phpDocumentor (but supported by Psalm) you may wish to prepend @psalm-
to the PHPDoc tag, so as to avoid confusing your IDE. If a @psalm
-prefixed tag is given, Psalm will use it in place of its non-prefixed counterpart.
This annotation is used to suppress issues. It can be used in function docblocks, class docblocks and also inline, applying to the following statement.
Function docblock example:
/**
* @psalm-suppress PossiblyNullOperand
*/
function addString(?string $s) {
echo "hello " . $s;
}
Inline example:
function addString(?string $s) {
/** @psalm-suppress PossiblyNullOperand */
echo "hello " . $s;
}
See Adding assertions.
This can be used to tell Psalm not to worry if a function/method returns null. It’s a bit of a hack, but occasionally useful for scenarios where you either have a very high confidence of a non-null value, or some other function guarantees a non-null value for that particular code path.
class Foo {}
function takesFoo(Foo $f): void {}
/** @psalm-ignore-nullable-return */
function getFoo(): ?Foo {
return rand(0, 10000) > 1 ? new Foo() : null;
}
takesFoo(getFoo());
This provides the same, but for false
. Psalm uses this internally for functions like preg_replace
, which can return false if the given input has encoding errors, but where 99.9% of the time the function operates as expected.
If you have a magic property getter/setter, you can use @psalm-seal-properties
to instruct Psalm to disallow getting and setting any properties not contained in a list of @property
(or @property-read
/@property-write
) annotations.
/**
* @property string $foo
* @psalm-seal-properties
*/
class A {
public function __get(string $name): ?string {
if ($name === "foo") {
return "hello";
}
}
public function __set(string $name, $value): void {}
}
$a = new A();
$a->bar = 5; // this call fails
Used to mark a class, property or function as internal to a given namespace. Psalm treats this slightly differently to
the PHPDoc @internal
tag. For @internal
, an issue is raised if the calling code is in a namespace completly
unrelated to the namespace of the calling code, i.e. not sharing the first element of the namespace.
In contrast for @psalm-internal
, the docbloc line must specify a namespace. An issue is raised if the calling code
is not within the given namespace.
As other tools do not support @psalm-internal
, it may only be used in conjuction with @internal
.
namespace A\B {
/**
* @internal
* @psalm-internal A\B
*/
class Foo { }
}
namespace A\B\C {
class Bat {
public function batBat(): void {
$a = new \A\B\Foo(); // this is fine
}
}
}
namespace A\C {
class Bat {
public function batBat(): void {
$a = new \A\B\Foo(); // error
}
}
}
Psalm supports PHPDoc’s type syntax, and also the proposed PHPDoc PSR type syntax.
A detailed write-up is found in Typing in Psalm