# Technical Documentation: vimeo/psalm

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/vimeo/psalm)

### Overview (`docs/README.md`)

# About Psalm

Psalm is a static analysis tool that attempts to dig into your program and find as many type-related bugs as possible.

It has a few features that go further than other similar tools:

- **Mixed type warnings**<br />
  If Psalm cannot infer a type for an expression then it uses a `mixed` placeholder type. `mixed` types can sometimes mask bugs, so keeping track of them helps you avoid a number of common pitfalls.

- **Intelligent logic checks**<br />
  Psalm keeps track of logical assertions made about your code, so `if ($a && $a) {}` and `if ($a && !$a) {}` are both treated as issues. Psalm also keeps track of logical assertions made in prior code paths, preventing issues like `if ($a) {} elseif ($a) {}`.

- **Property initialisation checks**<br />
  Psalm checks that all properties of a given object have values after the constructor is called.

- **Taint analysis**<br />
  Psalm can [detect security vulnerabilities](https://psalm.dev/articles/detect-security-vulnerabilities-with-psalm) in your code.
  
- **Language Server**<br />
  Psalm has a Language Server that’s [compatible with a range of different IDEs](https://psalm.dev/docs/running_psalm/language_server/).

- **Automatic fixes**<br />
  Psalm can [fix many of the issues it finds automatically](https://psalm.dev/docs/manipulating_code/fixing/).
  
- **Automatic refactoring**<br />
  Psalm can also [perform simple refactors](https://psalm.dev/docs/manipulating_code/refactoring/) from the command line.

## Example output

Given a file `implode_strings.php`:

```php
<?php
$a = ['foo', 'bar'];
echo implode($a, ' ');
```

```bash
> ./vendor/bin/psalm implode_strings.php
ERROR: InvalidArgument - somefile.php:3:14 - Argument 1 of implode expects `string`, `array` provided (see https://psalm.dev/004)
```

## Inspirations

There are two main inspirations for Psalm:

- Etsy's [Phan](https://github.com/etsy/phan), which uses nikic's [php-ast](https://github.com/nikic/php-ast) extension to create an abstract syntax tree
- Facebook's [Hack](http://hacklang.org/), a PHP-like language that supports many advanced typing features natively, so docblocks aren't necessary.

## Index

- Running Psalm:
    - [Installation](running_psalm/installation.md)
    - [Configuration](running_psalm/configuration.md)
    - Plugins
        - [Using plugins](running_psalm/plugins/using_plugins.md)
        - [Authoring plugins](running_psalm/plugins/authoring_plugins.md)
        - [How Psalm represents types](running_psalm/plugins/plugins_type_system.md)
    - [Command line usage](running_psalm/command_line_usage.md)
    - [IDE support](running_psalm/language_server.md)
    - Handling errors:
        - [Dealing with code issues](running_psalm/dealing_with_code_issues.md)
        - [Issue Types](running_psalm/issues.md)
    - [Checking non-PHP files](running_psalm/checking_non_php_files.md)
- Security analysis:
    - [Security Analysis in Psalm](security_analysis/index.md)
    - [Custom Taint Sources](security_analysis/custom_taint_sources.md)
    - [Custom Taint Sinks](security_analysis/custom_taint_sinks.md)
    - [Avoiding false-positives](security_analysis/avoiding_false_positives.md)
    - [Avoiding false-negatives](security_analysis/avoiding_false_negatives.md)
    - [Security analysis annotations](security_analysis/annotations.md)
    - [Taint Flow](security_analysis/taint_flow.md)
- Annotating code:
    - [Typing in Psalm](annotating_code/typing_in_psalm.md)
    - [Supported Annotations](annotating_code/supported_annotations.md)
    - [Template Annotations](annotating_code/templated_annotations.md)
    - [Type Variables](annotating_code/type_variables.md)
    - [The Purity Model](annotating_code/purity_model.md)
- Manipulating code:
    - [Fixing code](manipulating_code/fixing.md)
    - [Refactoring code](manipulating_code/refactoring.md)

---

### Contributing Index (`docs/contributing/index.md`)

# Contributing to Psalm

Psalm is made possible through the contributions of [hundreds of developers](https://github.com/vimeo/psalm/graphs/contributors).

Hopefully you can be one of them?

## Getting started

[Here’s a rough guide to the codebase](how_psalm_works.md).

[Here's the philosophy underpinning the Psalm’s development](philosophy.md).

I've also put together [a list of Psalm’s complexities](what_makes_psalm_complicated.md).

Are you looking for low-hanging fruit? Here are some [GitHub issues](https://github.com/vimeo/psalm/issues?q=is%3Aissue+is%3Aopen+label%3A%22easy+problems%22) that shouldn't be too difficult to resolve.

### Don’t be afraid!

One great thing about working on Psalm is that it’s _very_ hard to introduce any sort of type error in Psalm’s codebase. There are almost 5,000 PHPUnit tests, so the risk of you messing up (without the CI system noticing) is very small.

### Why static analysis is cool

Day-to-day PHP programming involves solving concrete problems, but they're rarely very complex. Psalm, on the other hand, attempts to solve a pretty hard collection of problems, which then allows it to detect a ton of bugs in PHP code without actually executing that code.

There's a lot of interesting theory behind the things Psalm does, too. If you want you can go very deep, though you don't need to know really any theory to improve Psalm.

Lastly, working to improve static analysis tools will also make you a better PHP developer – it'll help you think more about how values flow through your program.

### Guides

* [Editing callmaps](editing_callmaps.md)
* [Adding a new issue type](adding_issues.md)

## Pull Requests

Before you send a pull request, make sure you follow these guidelines:

Run integration checks locally: `composer tests`

If you're adding new features or fixing bugs, don’t forget to add tests!

---

### Security Analysis Index (`docs/security_analysis/index.md`)

# Security Analysis in Psalm

Psalm can attempt to find connections between user-controlled input (like `$_GET['name']`) and places that we don’t want unescaped user-controlled input to end up (like `echo "<h1>$name</h1>"` by looking at the ways that data flows through your application (via assignments, function/method calls and array/property access).

You can enable this mode with the `--taint-analysis` command line flag.  

Tainted input is anything that can be controlled, wholly or in part, by a user of your application. In taint analysis, tainted input is called a _taint source_.

Example sources:

 - `$_GET[‘id’]`
 - `$_POST['email']`
 - `$_COOKIE['token']`

 Taint analysis tracks how data flows from taint sources into _taint sinks_. Taint sinks are places you really don’t want untrusted data to end up.

Example sinks:

 - `<div id="section_<?= $id ?>">`
 - `$pdo->exec("select * from users where name='" . $name . "'")`

## Taint Types

Psalm recognises a number of taint types by default, defined in the [Psalm\Type\TaintKind](https://github.com/vimeo/psalm/blob/master/src/Psalm/Type/TaintKind.php) class:

- `sql` - used for strings that could contain SQL
- `ldap` - used for strings that could contain a ldap DN or filter
- `html` - used for strings that could contain angle brackets or unquoted strings
- `has_quotes` - used for strings that could contain unquoted strings
- `shell` - used for strings that could contain shell commands
- `callable` - used for callable strings that could be user-controlled
- `unserialize` - used for strings that could contain a serialized string
- `include` - used for strings that could contain a path being included
- `eval` - used for strings that could contain code
- `ssrf` - used for strings that could contain text passed to Curl or similar
- `url_component` - used for strings that could contain URL syntax (`/`, `?`, `&`, `#`...) placed in the path, query or fragment of a URL
- `url_path` - used for strings that could be a `.` or `..` segment of the path of a URL, even URL-encoded
- `file` - used for strings that could contain a path
- `cookie` - used for strings that could contain a http cookie
- `header` - used for strings that could contain a http header
- `user_secret` - used for strings that could contain user-supplied secrets
- `system_secret` - used for strings that could contain system secrets

You're also free to define your own taint types when defining custom taint sources – they're just strings.

## Taint Sources

Psalm defines the following default taint sources:

 - the `$_GET`, `$_POST`, `$_COOKIE` and `$_REQUEST` server variables;
 - the entries of `$_SERVER` the client sends: the request headers (`HTTP_*`), the URI and what is taken from it (`REQUEST_URI`, `QUERY_STRING`, `PATH_INFO`, `PHP_SELF`, `argv`, ...), `REQUEST_METHOD`, `CONTENT_TYPE` and the HTTP authentication credentials, the same entries of a redirected request (`REDIRECT_*`), and any entry read with a key that is not a literal;
 - the names, types and full paths of the uploaded files in `$_FILES`;
 - reading from the input stream: `fopen()`, `file_get_contents()` and `file()` called with a literal `php://input` or `php://stdin` path, and the stream reading functions (`fgets()`, `fread()`, `stream_get_contents()`, ...) applied to such a handle;
 - the predefined `STDIN` constant (the `php://stdin` stream).
 - reading from the network: `socket_read()`, the data `socket_recv()`, `socket_recvfrom()` and `socket_recvmsg()` write to their by-reference parameter, `stream_socket_recvfrom()`, `curl_exec()` and `curl_multi_getcontent()`, and the streams opened with `fsockopen()`, `pfsockopen()`, `stream_socket_client()`, `stream_socket_accept()` and `socket_export_stream()` (so reading from them with `fgets()`, `fread()`, ... is a source too).
 - DNS answers, which whoever runs the name servers of a domain chooses: `dns_get_record()`, the hosts `getmxrr()` writes to its by-reference parameter, and `gethostbyaddr()`.
 - the command-line options `getopt()` returns, which whoever runs the script chooses.
 - exceptions, since the analysis does not follow them from where they are thrown to where they are caught: their message (`getMessage()`), their trace (`getTraceAsString()`) and their string form, and the variable of a `catch` block, so dumping a caught exception (`print_r()`, `var_export()`) is a source too.

You can also [define your own taint sources](custom_taint_sources.md).

## Taint Sinks

Psalm currently defines a number of different sinks for builtin functions and methods, including `echo`, `include`, `header`.

What is written to a stream opened on a literal `php://output` path, which is the response, or `php://stdout`, which is the response under the CGI SAPI, is a sink as what `echo` outputs is: `file_put_contents()` to such a path, and `fwrite()`, `fputs()`, `fputcsv()`, `fprintf()`, `vfprintf()`, `stream_copy_to_stream()` and the `fwrite()` and `fputcsv()` methods of `SplFileObject` on a stream opened with `fopen()` or `new SplFileObject()` on such a path in the same function, and held by its variables.

You can also [define your own taint sinks](custom_taint_sinks.md).

## Avoiding False-Positives

Nobody likes to wade through a ton of false-positives – [here’s a guide to avoiding them](avoiding_false_positives.md).

## Limitations

Taint Analysis relies on not making any mistakes when escaping values, e.g.

```php
$sql = 'SELECT * FROM users WHERE id = ' . $mysqli->real_escape_string((string) $_GET['id']);

$html = "
  <img src=" . htmlentities((string) $_GET['img']) . " alt='' />
  <a href='" . htmlentities((string) $_GET['a1']) . "'>Link 1</a>
  <a href='" . htmlentities((string) $_GET['a2']) . "'>Line 2</a>";

// Details:
//    $id  = 'id'                   - Missing quotes
//    $img = '/ onerror=alert(1)'   - Missing quotes
//    $a1  = 'javascript:alert(1)'  - Normal inline JavaScript
//    $a2  = '/' onerror='alert(1)' - Pre PHP 8.1, single quotes are not escaped by default
// Test:
//    /?id=id&img=%2F+onerror%3Dalert%281%29&a1=javascript%3Aalert%281%29&a2=%2F%27+onerror%3D%27alert%281%29
```

To avoid these issues, use Parameterised Queries for SQL and Commands (e.g. `exec`); and a context-aware templating engine for HTML. Then use the [literal-string](https://psalm.dev/docs/annotating_code/type_syntax/scalar_types/#literal-string) type to ensure sensitive strings are defined in your application (i.e. have been written by a developer).

## Security Issues

The issues of security analysis (`TaintedHtml`, `TaintedSql`, ...) flag potential vulnerabilities rather than type errors or code-quality problems. To tell them apart, Psalm's human-readable reports (`console`, `compact`, `table`, `by-issue-level` and `phpstorm`) show them under a `SECURITY` header instead of `ERROR`:

```
SECURITY: TaintedHtml - src/index.php:2:1 - Detected tainted HTML
```

A security issue configured with `errorLevel="info"` is still shown as `INFO`. Machine-readable reports (JSON, checkstyle, SARIF, ...) keep their usual severities; the JSON and XML reports also include an `is_security` field.

Plugins can mark their own issues the same way by implementing the `Psalm\Issue\SecurityIssue` interface.

## Using Baseline With Taint Analysis

Since taint analysis is performed separately from other static code analysis, it makes sense to use a separate baseline for it.

You can use --use-baseline=PATH option to set a different baseline for taint analysis.

## Viewing Results in a User Interface

Psalm supports the [SARIF](http://docs.oasis-open.org/sarif/sarif/v2.0/csprd01/sarif-v2.0-csprd01.html) standard for exchanging static analysis results. This enables you to view the results in any SARIF compatible software, including the taint flow.

### GitHub Code Scanning

[GitHub code scanning](https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/about-code-scanning) can be set up by using the [Psalm GitHub Action](https://github.com/marketplace/actions/psalm-static-analysis-for-php).

Alternatively, the generated SARIF file can be manually uploaded as described in [the GitHub documentation](https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/uploading-a-sarif-file-to-github).

The results will then be available in the "Security" tab of your repository.

### Other SARIF compatible software

To generate a SARIF report run Psalm with the `--report` flag and a `.sarif` extension. For example:

```bash
psalm --report=results.sarif
```

## Debugging the taint graph

Psalm can output the taint graph using the DOT language. This is useful when expected taints are not detected. To generate a DOT graph run Psalm with the `--dump-taint-graph` flag. For example:

```bash
psalm --taint-analysis --dump-taint-graph=taints.dot
dot -Tsvg -o taints.svg taints.dot
```

---

### Annotating Code Adding Assertions (`docs/annotating_code/adding_assertions.md`)

# Adding assertions

Psalm has five docblock annotations that allow you to specify that a function verifies facts about variables and properties:

- `@psalm-assert` (used when throwing an exception)
- `@psalm-assert-if-true`/`@psalm-assert-if-false` (used when returning a `bool`)
- `@psalm-if-this-is`/`@psalm-this-out` (used when calling a method)

A list of acceptable assertions [can be found here](assertion_syntax.md).

## Examples

If you have a class that verified its input is an array of strings, you can make that clear to Psalm:

```php
<?php
/** @psalm-assert string[] $arr */
function validateStringArray(array $arr) : void {
    foreach ($arr as $s) {
        if (!is_string($s)) {
          throw new UnexpectedValueException('Invalid value ' . gettype($s));
        }
    }
}
```

This enables you to call the `validateStringArray` function on some data and have Psalm understand that the given data *must* be an array of strings:

```php
<?php
function takesString(string $s) : void {}
function takesInt(int $s) : void {}

function takesArray(array $arr) : void {
    takesInt($arr[0]); // this is fine

    validateStringArray($arr);

    takesInt($arr[0]); // this is an error

    foreach ($arr as $a) {
        takesString($a); // this is fine
    }
}
```

Similarly, `@psalm-assert-if-true` and `@psalm-assert-if-false` will filter input if the function/method returns `true` and `false` respectively:

```php
<?php
class A {
    public function isValid() : bool {
        return (bool) rand(0, 1);
    }
}
class B extends A {
    public function bar() : void {}
}

/**
 * @psalm-assert-if-true B $a
 */
function isValidB(A $a) : bool {
    return $a instanceof B && $a->isValid();
}

/**
 * @psalm-assert-if-false B $a
 */
function isInvalidB(A $a) : bool {
    return !$a instanceof B || !$a->isValid();
}

function takesA(A $a) : void {
    if (isValidB($a)) {
        $a->bar();
    }

    if (isInvalidB($a)) {
        // do something
    } else {
        $a->bar();
    }

    $a->bar(); //error
}
```

As well as getting Psalm to understand that the given data must be a certain type, you can also show that a variable must be not null:

```php
<?php
/**
 * @psalm-assert !null $value
 */
function assertNotNull($value): void {
  // Some check that will mean the method will only complete if $value is not null.
}
```

And you can check on null values:

```php
<?php
/**
 * @psalm-assert-if-true null $value
 */
function isNull($value): bool {
  return ($value === null);
}
```

### Asserting return values of methods

You can also use the `@psalm-assert-if-true` and `@psalm-assert-if-false` annotations to assert return values of
methods inside classes. As you can see, Psalm even allows you to specify multiple annotations in the same DocBlock:

```php
<?php
class Result {
    /**
     * @var ?Exception
     */
    private $exception;

    /**
     * @psalm-assert-if-true Exception $this->exception
     * @psalm-assert-if-true Exception $this->getException()
     */
    public function hasException(): bool {
        return $this->exception !== null;
    }

    public function getException(): ?Exception {
        return $this->exception;
    }

    public function foo(): void {
        if( $this->hasException() ) {
            // Psalm now knows that $this->exception is an instance of Exception
            echo $this->exception->getMessage();
        }
    }
}

$result = new Result;

if( $result->hasException() ) {
    // Psalm now knows that $result->getException() will return an instance of Exception
    echo $result->getException()->getMessage();
}
```

Please note that the example above only works if you enable [method call memoization](https://psalm.dev/docs/running_psalm/configuration/#memoizemethodcallresults)
in the config file or annotate the class as [immutable](https://psalm.dev/docs/annotating_code/supported_annotations/#psalm-immutable).


You can use `@psalm-this-out` to change the template arguments of a method after a method call, to reflect changes to the object's internal state.  
You can also make assertions on the object's template arguments using `@psalm-if-this-is`.  


```php
<?php

/**
 * @template T
 */
class a {
    /**
     * @var list<T>
     */
    private array $data;
    /**
     * @param T $data
     */
    public function __construct($data) {
        $this->data = [$data];
    }
    /**
     * @template NewT
     * 
     * @param NewT $data
     * 
     * @psalm-this-out self<T|NewT>
     * 
     * @return void
     */
    public function addData($data) {
        /** @var self<T|NewT> $this */
        $this->data []= $data;
    }
    /**
     * @template NewT
     * 
     * @param NewT $data
     * 
     * @psalm-this-out self<NewT>
     * 
     * @return void
     */
    public function setData($data) {
        /** @var self<NewT> $this */
        $this->data = [$data];
    }
    /**
     * @psalm-if-this-is a<int>
     */
    public function test(): void {
    }
}

$i = new a(123);
// OK - $i is a<123>
$i->test();

$i->addData(321);
// OK - $i is a<123|321>
$i->test();

$i->setData("test");
// IfThisIsMismatch - Class is not a<int> as required by psalm-if-this-is
$i->test();
```

`@psalm-this-out` (and its aliases `@psalm-self-out`, `@phpstan-self-out` and `@phpstan-this-out`) also accepts a conditional type keyed off one of the method's parameters, e.g. `@phpstan-this-out ($key is null ? static<TKey|int, TValue> : $this)`. The branch is resolved from the argument passed at each call site, so a call that omits `$key` (or passes `null`) infers a different resulting type than one that passes a concrete value. `@psalm-if-this-is` does not support this form, since its condition must be known before the call's arguments are analyzed.

---

### Annotating Code Assertion Syntax (`docs/annotating_code/assertion_syntax.md`)

# Assertion syntax

Psalm’s [assertion annotation](adding_assertions.md) 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
<?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
<?php
/** @psalm-assert !int $foo */
```

This asserts that `$bar` is not an object of type `SomeObjectType`:
```php
<?php
/** @psalm-assert !SomeObjectType $bar  */
```

## Bool assertions

This asserts that `$bar` is `true`:
```php
<?php
/** @psalm-assert true $bar  */
```

This asserts that `$bar` is not `false`:
```php
<?php
/** @psalm-assert !false $bar  */
```

## Equality assertions

Psalm also supports the equivalent of `assert($some_int === $other_int)` in the form
```php
<?php
/** @psalm-assert =int $some_int */
```

There are two differences between the above assertion and 

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

Firstly, the negation of `=int` has no meaning:

```php
<?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.

---

### Annotating Code Purity Model (`docs/annotating_code/purity_model.md`)

# The Purity Model

Psalm describes what a function, method or closure may do as a set of **capabilities**:
permissions to perform particular side effects, such as writing a property or printing. The
model comes from Hack's [contexts and capabilities](https://docs.hhvm.com/hack/contexts-and-capabilities/introduction).
It replaces the three fixed levels of Psalm 6 (`@psalm-pure`, `@psalm-mutation-free` and
`@psalm-external-mutation-free`), which are now three points in a larger space.

This page explains how the model works. The annotations are listed in
[Supported Annotations](supported_annotations.md#purity-and-capabilities). The examples only
mark the issues they are about: Psalm also suggests annotations for the unannotated code in them
(see [Inferring annotations](#inferring-annotations)).

## Capabilities

| Capability         | Allows                                                                          |
|--------------------|---------------------------------------------------------------------------------|
| `read-props`       | reading properties of mutable objects, including `$this` (immutable objects never need it, nor objects the caller created with `new` from a class whose contract needs at most `read-props\|write-this-props\|write-refs`, or whose constructor can't keep a reference to them, see [Method calls](#method-calls)) |
| `write-this-props` | writing or unsetting properties of `$this`                                      |
| `write-props`      | writing or unsetting properties of any other object                             |
| `read-globals`     | reading static properties and superglobals, and binding `global` variables      |
| `write-globals`    | writing them, including through a bound `global` variable, and using `static` variables |
| `write-refs`       | writing through by-reference parameters and other references into another scope |
| `io`               | `echo`, `print`, `exit` with a message, and builtins with side effects (`random_int`, `file_put_contents`, …) |
| `time`             | reading the clock (`time`, `microtime`, `hrtime`, `date` and `getdate` without a timestamp, …) |

Builtins touching process-wide state (`mt_rand`, `ini_set`, `spl_autoload_register`, …) need
`write-globals` instead of `io`.

Two names stand for the extremes: `pure` is the empty set, a
[pure function](https://en.wikipedia.org/wiki/Pure_function) whose result depends only on its
arguments, and `impure` is every capability. A set is written with `|` or commas:
`read-props|write-this-props`.

A function-like may only do something, or call something, when its own set contains every
capability that needs. Code without an annotation is `impure`: it may do anything, and nothing
inside it is checked.

Each name means that one capability only. Writing does not include reading, so `$this->n++`
needs `read-props|write-this-props`, and code that writes both `$this` and other objects needs
`write-this-props|write-props`. `write-props` does not include `write-this-props`, and
`write-globals` does not include `read-globals`. A plain assignment only needs the write
capability: `$this->n = 0` needs `write-this-props`, `Counter::$count = 0` needs `write-globals`.
Using `$this` at all needs `read-props` or `write-this-props`, so a setter returning `$this` may be
`write-this-props`.

```php
<?php
final class Counter {
    public static int $count = 0;
    private int $n = 0;

    /** @psalm-capabilities read-props|write-this-props */
    public function next(): int {
        return ++$this->n;
    }

    /** @psalm-capabilities write-this-props */
    public function nextWrong(): int {
        return ++$this->n; // ImpurePropertyFetch: The context is write-this-props but accessing a property on a mutable object requires read-props
    }
}

/** @psalm-capabilities read-globals */
function total(): int {
    return Counter::$count;
}

/** @psalm-capabilities read-globals */
function resetTotal(): int {
    Counter::$count = 0; // ImpureStaticProperty: The context is read-globals but writing a static property requires write-globals
    return 0;
}
```

### Global state

Values reached from global state stay bound to it. An object read from a static property, a
superglobal or a `global` variable, returned by a function that may read globals, or fetched from
such an object, can only have its properties written, its mutating methods called, or be passed
to a function that may write properties, by code that has `write-globals`. This makes
`read-globals` a read-only view of global state, like Hack's `readonly` values:

```php
<?php
final class Config {
    public string $env = "prod";
    public static ?Config $instance = null;
}

/** @psalm-capabilities read-globals */
function config(): ?Config {
    return Config::$instance;
}

/** @psalm-capabilities read-globals|write-props */
function tamper(): void {
    $config = config();
    if ($config !== null) {
        $config->env = "dev"; // ImpurePropertyAssignment: The context is write-props|read-globals but property assignment to Config::$env on an object reached from global state requires write-props|write-globals
    }
}
```

A new object the caller created (see [Method calls](#method-calls)) is not global state itself,
even when its constructor read global state, or when it is a clone of an object reached from
global state: writing its own properties is free. What it holds may be global state, so writing
another object through it, or calling a method that does, costs `write-globals` too.

## Annotations

Every purity annotation is a name for a capability set:

| Annotation                      | Used on                          | Capabilities                                       |
|---------------------------------|----------------------------------|----------------------------------------------------|
| `@psalm-pure`                   | function, method, class          | `pure`; on a class, properties can't be used at all |
| `@psalm-capabilities <set>`     | function, method, closure, class | `<set>`                                            |
| `@psalm-impure`                 | function, method                 | `impure`, written out                              |
| `@psalm-immutable`              | class                            | `read-props` for every method, and every property is readonly |
| `@psalm-mutable`                | class                            | `impure`, written out                              |
| `@psalm-mutation-free`          | function, method, class          | `read-props` (legacy)                              |
| `@psalm-external-mutation-free` | function, method, class          | `read-props\|write-this-props\|write-refs` (legacy) |
| none                            |                                  | `impure`                                           |

`@pure`, `@phpstan-pure`, `#[Psalm\Pure]` and `#[JetBrains\PhpStorm\Pure]` mean the same as
`@psalm-pure`; `#[Psalm\Immutable]` and `#[JetBrains\PhpStorm\Immutable]` the same as
`@psalm-immutable`; `#[Psalm\ExternalMutationFree]` the same as `@psalm-external-mutation-free`.

### Capability aliases

A capability set can be named once with a type alias and used in `@psalm-capabilities`, in
closure types and as a purity argument, like Hack's context constants. Aliases of other classes
are imported with `@psalm-import-type`:

```php
<?php
/** @psalm-type Storage = write-props|io */
final class Repo {
    /** @psalm-capabilities Storage */
    public function save(): void { echo "saved"; }
}

/** @psalm-import-type Storage from Repo */
final class Service {
    /**
     * @psalm-capabilities Storage
     * @param Closure[Storage](): void $after
     */
    public function run(Repo $repo, Closure $after): void {
        $repo->save();
        $after();
    }
}
```

### Conditional capabilities

What a call requires may depend on its arguments, like a conditional return type. Each call
requires the branch its arguments select. Where the arguments may go either way, or there is no
call (a callable taken from the function), it requires both. The body may do what either branch
allows.

```php
<?php
/** @psalm-capabilities ($seed is null ? io : pure) */
function makeId(?int $seed = null): int {
    return $seed ?? random_int(0, PHP_INT_MAX);
}

/** @psalm-pure */
function fromSeed(int $seed): int {
    return makeId($seed); // fine: $seed can't be null
}

/** @psalm-pure */
function fresh(): int {
    return makeId(); // ImpureFunctionCall: The context is pure but function call on makeid requires io
}
```

The constructor of `MongoDB\BSON\ObjectId` is stubbed this way: without an id it generates one
from the clock and a counter of the process, while given an id it only validates it.

### Closures

Closures don't need an annotation. Psalm infers their capabilities from their bodies and keeps
them in their type, for example `Closure[io](int): void` (see
[callable types](type_syntax/callable_types.md#pure-callables)). Creating a closure is not an
effect: a pure function may build and return an impure closure. Calling it, or passing it to a
parameter that expects fewer capabilities, is checked.

A closure that captures a variable by reference (`use (&$x)`) shares it with the enclosing
scope: reading it needs `read-props` and writing it `write-this-props`, as if it were a property
of the closure, so such a closure is not pure. The enclosing scope may still call it freely,
since the variable is its own, and only needs a capability when the variable is shared further:
`write-refs` for a by-reference parameter, `write-globals` for a global.

```php
<?php
/**
 * @psalm-pure
 * @param list<int> $numbers
 */
function sum(array $numbers): int {
    $total = 0;
    $add = function (int $value) use (&$total): void { $total += $value; };
    foreach ($numbers as $number) {
        $add($number); // fine: $total belongs to sum()
    }
    return $total;
}

/**
 * @psalm-pure
 * @param Closure[pure](int): void $callback
 */
function callWithOne(Closure $callback): int {
    $callback(1);
    return 1;
}

/** @psalm-pure */
function leak(): int {
    $total = 0;
    return callWithOne(function (int $value) use (&$total): void { $total += $value; }); // ArgumentTypeCoercion: Argument 1 of callWithOne expects Closure[pure](int):void, but parent type Closure[read-props|write-this-props](int):void provided
}
```

Likewise, an object the enclosing scope created and the closure captures, by value or by
reference, is state of the closure, as an object a class instance creates is its own. So are the
objects in a captured array the enclosing scope created, and the state of a closure that a closure
created in it captures. Writing that state, or calling a method that writes it, needs
`write-this-props`, and the enclosing scope may call the closure freely. An object the enclosing
scope did not create, like a parameter, belongs to someone else: writing it needs `write-props`.

## Class-level contracts

`@psalm-capabilities` on a class or interface is a contract for the class and for everything that
extends or implements it. Every method of the class gets those capabilities, and may declare fewer
but not more:

```php
<?php
/** @psalm-capabilities io */
final class Logger {
    public static int $level = 0;

    public function log(string $message): void {
        echo $message; // fine: the class allows io
    }

    /** @psalm-capabilities io|write-globals */
    public function setLevel(int $level): void { // ImpureFunctionCall: setLevel is marked @psalm-capabilities write-globals|io but its containing class allows fewer capabilities, @psalm-capabilities io
        self::$level = $level;
    }
}
```

A class extending or implementing one with a contract must have a contract that fits inside it;
otherwise Psalm reports [ImmutableDependency](../running_psalm/issues/ImmutableDependency.md).
A marker interface, declaring no method or property and inheriting none, is pure without an
annotation, as it does nothing; unlike an interface marked `@psalm-pure`, it caps none of its
implementers.
Abstract methods, and the methods of interfaces, have no body to infer anything from, so each of
them needs its own annotation, even inside a class with a contract
([MissingAbstractPureAnnotation](../running_psalm/issues/MissingAbstractPureAnnotation.md)); use
`@psalm-impure` for one that may do anything.

## How calls are charged

A caller normally needs every capability of the function-likes it calls. Two kinds of calls are
charged more precisely.

### Method calls

A method that needs `write-this-props` writes its own `$this`, which may or may not be the
caller's. The call is charged according to the receiver:

- the caller's own `$this`, also when a call on it of a method returning its receiver gives it
  back (see [Fluent calls](#fluent-calls)): `write-this-props`;
- an object the caller created with `new`, from a class whose contract needs at most
  `read-props|write-this-props|write-refs`, or whose constructor can't keep a reference to it:
  nothing, as nobody else can see it change;
- any other object, including a parameter, a property of `$this`, or an object returned by
  another call: `write-props`.

```php
<?php
/** @psalm-capabilities read-props|write-this-props */
final class Counter {
    private int $n = 0;

    public function inc(): void {
        $this->n++;
    }

    public function incTwice(): void {
        $this->inc(); // fine: costs write-this-props
        $this->inc();
    }

    public function get(): int {
        return $this->n;
    }
}

/** @psalm-pure */
function countTwice(): int {
    $counter = new Counter();
    $counter->inc(); // fine: $counter was created here
    $counter->inc();
    return $counter->get();
}

/** @psalm-capabilities read-props */
function bump(Counter $counter): int {
    $counter->inc(); // ImpureMethodCall: The context is read-props but method Counter::inc requires write-props
    return $counter->get();
}
```

Reading or unsetting a property gets the same waiver: it is free on an object the caller created
with `new`, from a class whose contract needs at most `read-props|write-this-props|write-refs`, as
nobody else can change it. Reading a property of any other mutable object, including `$this`, a
parameter or an object held in a property, costs `read-props`, whatever the class's contract:

```php
<?php
/** @psalm-capabilities read-props|write-this-props */
final class Tally {
    public int $n = 0;

    public function inc(): void {
        $this->n++;
    }
}

/** @psalm-pure */
function tallyTwice(): int {
    $tally = new Tally();
    $tally->inc();
    $tally->inc();
    return $tally->n; // fine: $tally was created here
}

/** @psalm-pure */
function currentTally(Tally $tally): int {
    return $tally->n; // ImpurePropertyFetch: The context is pure but accessing a property on a mutable object requires read-props
}
```

Without a class-level contract, calling a method on an object the caller created with `new`, and
reading or writing its properties, is still free, as long as the constructor can't keep a reference
to the new object anywhere. Only
three things can hand `$this` to someone else: writing another object (`write-props`), global state
(`write-globals`) or a by-reference parameter (`write-refs`). So a constructor that needs none of
these qualifies, and so does a class without a constructor:

```php
<?php
final class Greeting {
    /** @var list<string> */
    private array $words = [];

    /** @psalm-capabilities read-props */
    public function __construct(string $first) {
        $this->words[] = $first;
    }

    /** @psalm-capabilities read-props|write-this-props */
    public function add(string $word): void {
        $this->words[] = $word;
    }

    /** @psalm-capabilities read-props */
    public function text(): string {
        return implode(" ", $this->words);
    }
}

/** @psalm-pure */
function hello(): string {
    $greeting = new Greeting("hello");
    $greeting->add("world"); // fine: the constructor can't hand $greeting to anyone
    return $greeting->text();
}
```

A constructor without a purity annotation qualifies too when it is trivial: it does nothing, or only
assigns its parameters (or constant values) to properties its class declares, promoted ones included.
Such a constructor needs `write-this-props` without being annotated (nothing at all if it is empty), so
neither `new` nor its class needs an annotation for the waiver. Any other statement makes it non-trivial:
a call (`parent::__construct()` included), a by-reference parameter, a default value that creates an
object or calls something, a property with hooks or one the class doesn't declare before the
constructor, or `$this` stored anywhere. A non-trivial constructor without an annotation may do
anything, as any unannotated method. So may a trivial constructor run for a class that redeclares one
of the properties it assigns with a hook (PHP 8.4), or by `new static()` / `new $class()` where the
class may be extended: the hook may do anything.

```php
<?php
final class Point {
    public int $z = 0;

    public function __construct(public int $x, public int $y) {}
}

/** @psalm-pure */
function lift(int $x, int $y): Point {
    $point = new Point($x, $y);
    $point->z = 1; // fine: Point's constructor is trivial
    return $point;
}
```

A constructor that may store `$this` somewhere loses the waiver. Here the constructor registers
every new object in a static property, so calling a method on the new object costs what it would
on any other one. The object is also reached from global state now, which adds `write-globals`:

```php
<?php
final class Registered {
    /** @var list<Registered> */
    public static array $all = [];

    public int $uses = 0;

    /** @psalm-capabilities read-globals|write-globals */
    public function __construct() {
        self::$all[] = $this;
    }

    /** @psalm-capabilities read-props|write-this-props */
    public function use(): void {
        $this->uses++;
    }
}

/** @psalm-capabilities read-globals|write-globals */
function register(): Registered {
    $registered = new Registered();
    $registered->use(); // ImpureMethodCall: The context is read-globals|write-globals but method Registered::use requires write-props|write-globals
    return $registered;
}
```

A constructor that writes another object, such as linking the new object to a parent passed to
it, or that writes a by-reference parameter, loses it the same way.

A `clone` is a new object too, by the same rule: the copy is free to mutate unless the class's
`__clone` needs `write-props`, `write-globals` or `write-refs`, and so may hand the copy to someone
else. A class-level contract keeps the waiver, for a clone as for a new object:

```php
<?php
final class Tracked {
    /** @var list<Tracked> */
    public static array $copies = [];

    public int $uses = 0;

    /** @psalm-capabilities read-props|read-globals|write-globals */
    public function __clone() {
        self::$copies[] = $this;
    }

    /** @psalm-capabilities read-props|write-this-props */
    public function use(): void {
        $this->uses++;
    }
}

/** @psalm-capabilities read-props|read-globals|write-globals */
function copyTracked(Tracked $tracked): Tracked {
    $copy = clone $tracked;
    $copy->use(); // ImpureMethodCall: The context is read-props|read-globals|write-globals but method Tracked::use requires write-props
    return $copy;
}
```

When the class isn't known exactly, there is no waiver: `new static()` in a class that may be
extended, and `new $class()`, may run the constructor of a subclass that keeps a reference:

```php
<?php
/** @psalm-consistent-constructor */
class Item {
    public int $count = 0;

    /** @psalm-capabilities read-props|write-this-props */
    public function bump(): void {
        $this->count++;
    }
}

/** @psalm-capabilities read-props|write-this-props */
function makeItem(): Item {
    $item = new Item();
    $item->bump(); // fine: an Item, whose constructor can't keep $item
    return $item;
}

/**
 * @param class-string<Item> $class
 * @psalm-capabilities read-props|write-this-props
 */
function makeAny(string $class): Item {
    $item = new $class();
    $item->bump(); // ImpureMethodCall: The context is read-props|write-this-props but method Item::bump requires write-props
    return $item;
}
```

This waiver covers calling methods, and writing and reading properties: reading a property of
such an object directly is free too, as calling a `read-props` method on it is. What the property
holds is another matter: reading a property of an object stored in it costs `read-props`, as that
object may be shared.

The `write-this-props` that a class purity template of the receiver is bound to
(`Doer[write-this-props]`, see [Purity templates](#purity-templates)) is charged the same way,
except that it is never waived for a new object. A receiver reached from
[global state](#global-state) also costs `write-globals`.

### Fluent calls

A method returns its receiver if it declares `@return $this`, or if no override can replace it
(it is private, final or in a final class) and each of its returns is `return $this;`. A call on
`$this` of such a method gives back `$this`, so a fluent chain on `$this` only mutates `$this`,
and so does writing a property of what the chain returns. `@return static` is not enough: the
method may return another instance of the class.

`@return $this` is a promise, checked like a return type: the method and every override of it may
only return `$this`, or a call on it of another method returning its receiver; any other return is
an [InvalidReturnStatement](../running_psalm/issues/InvalidReturnStatement.md).

```php
<?php
abstract class Query {
    /** @var list<string> */
    private array $conditions = [];

    /**
     * @return $this
     * @psalm-capabilities read-props|write-this-props
     */
    public function where(string $condition): static {
        $this->conditions[] = $condition;
        return $this;
    }

    /** @psalm-capabilities read-props|write-this-props */
    public function whereBetween(string $from, string $to): static {
        return $this->where($from)->where($to); // fine: costs write-this-props
    }

    /** @psalm-capabilities read-props */
    public function copy(): static {
        return clone $this;
    }

    /** @psalm-capabilities read-props|write-this-props */
    public function copyWhere(string $condition): static {
        return $this->copy()->where($condition); // ImpureMethodCall: The context is read-props|write-this-props but method Query::where requires write-props
    }
}
```

### By-reference arguments

A call to a function-like with `write-refs` does not cost `write-refs` itself. Each argument
passed by reference costs what writing it directly would cost: nothing for a local variable,
`write-refs` for one of the caller's own by-reference parameters, `write-this-props` for a property
of `$this`, `write-props` for another object's property, and `write-globals` for global state.
The callee itself still only has `write-refs`. This includes builtins such as `sort()`, so a pure
function may sort a local array.

```php
<?php
final class Stats {
    public static int $n = 0;
}

/** @psalm-capabilities write-refs */
function inc(int &$i): void {
    $i++;
}

/** @psalm-capabilities write-refs */
function update(int &$ref): void {
    $local = 0;
    inc($local);    // fine: $local belongs to update()
    inc($ref);      // fine: like writing $ref directly, costs write-refs
    // both reported on the next line:
    // ImpureStaticProperty: The context is write-refs but reading a static property requires read-globals
    // ImpureFunctionCall: The context is write-refs but function call on inc requires write-globals
    inc(Stats::$n);
}
```

### Implicit calls

Everything a function-like does is checked, including what happens implicitly: `clone` calls
`__clone`, string interpolation and casts call `__toString`, `$object()` calls `__invoke`, array
access on objects calls the `ArrayAccess` methods, `throw new` and `new $className` call the
constructor (an unknown class may do anything), and `foreach` over an object calls its iteration
methods (see [Iterators and generators](#iterators-and-generators)). A callable string or array
whose target is not known may do anything, so a pure function may not call one.

### Destructors

Destroying an object calls its destructor, where the object dies. So a pure function may not
hold, in a local variable, an object it created with `new` whose `__destruct` has effects, unless
the object leaves the function (returned, stored, passed on, captured). Nor may it `unset()` a
variable, property or array element holding such an object, overwrite one by assigning it, or
discard one (`new Guard();`).

Only the declared destructors of the known classes of the dropped value count: a `mixed`,
`object` or template value is not charged. A property is assumed to hold nothing yet in its
class's constructor (and to be kept by the original in `__clone`), and a variable first assigned
in a loop body to hold a value like the one assigned when it is assigned again, the previous
iteration's.

### Parameter default values

Parameter default values are evaluated like in Hack: with no capabilities at all, or with
`read-globals|write-globals` when the function-like has `write-globals`, whatever else it may do.
Only function-likes without a purity annotation may use anything in a default value, so `new` in
the defaults of unannotated code stays free.

## Purity templates

Sometimes what a function does depends on what it is given: `array_map()` is pure when its
callback is pure. A **purity template** is a template parameter whose value is a capability set
instead of a type. It is declared with
[`@psalm-purity-template`](supported_annotations.md#psalm-purity-template).

### Binding a purity template

Purity arguments are written in square brackets, before any type arguments, as in Hack:

- `Closure[P](int): int`, `callable[pure](): void`: the purity of a callable;
- `Handler[pure]`, `Box[io]<int>`: the purity argument of a class with a purity template;
- `@extends Handler[pure]`, `@implements Iterator[pure]<int, string>`: a subclass binding it.

The purity templates of a class come after its type templates, whatever the order of the
`@template` and `@psalm-purity-template` tags. A class with `@template T` and
`@psalm-purity-template P` is used as `Box[pure]<int>`, as `Box<int>` for its default purity, or
as `Box[pure]` for its default type arguments. Several purity arguments are separated by commas
(`Pair[pure, io]<int>`), and each is a capability set (`write-props|io`) or a purity template.
An empty set is written `pure`; `Handler[]` is an array of `Handler`.

Purity templates are covariant: a `Handler[pure]` can be used where a `Handler[io]` is expected.

The bounds of type templates may use purity templates, which are then inferred with them: a
class with `@template TIterator as Traversable[P]<K, V>` and `@psalm-purity-template P`,
constructed with a `Generator[pure]<int, string, mixed, void>`, is a
`Foo[pure]<int, string, Generator[pure]<int, string, mixed, void>>`.

### `@psalm-purity-from-template`

[`@psalm-purity-from-template P`](supported_annotations.md#psalm-purity-from-template) says that
each call needs the function-like's own capabilities plus whatever `P` is bound to at that call.
Inside the body, calling a closure whose purity is `P` is not an effect: each caller pays for it,
like with Hack's `[ctx $f]` contexts. It works for functions, methods, static methods and constructors. `P` may be a purity template of
the function-like or of its class, or a type template bound to a closure or callable type.

With a class-level template, subclasses decide the purity:

```php
<?php
/** @psalm-purity-template P */
abstract class Handler {
    /**
     * @psalm-pure
     * @psalm-purity-from-template P
     */
    abstract public function handle(string $input): string;
}

/** @extends Handler[pure] */
final class Upper extends Handler {
    /** @psalm-pure */
    public function handle(string $input): string {
        return strtoupper($input);
    }
}

/** @extends Handler[io] */
final class Printer extends Handler {
    /** @psalm-capabilities io */
    public function handle(string $input): string {
        echo $input;
        return $input;
    }
}

/** @psalm-pure */
function viaUpper(Upper $handler): string {
    return $handler->handle('a'); // fine: Upper binds P to pure
}

/**
 * @psalm-pure
 * @param Handler[pure] $handler
 */
function viaPureHandler(Handler $handler): string {
    return $handler->handle('a'); // fine
}

/**
 * @psalm-pure
 * @psalm-purity-template Q
 * @param Handler[Q] $handler
 * @psalm-purity-from-template Q
 */
function viaSomeHandler(Handler $handler): string {
    return $handler->handle('a'); // fine: pure when given an Upper, io when given a Printer
}

/** @psalm-pure */
function viaAnyHandler(Handler $handler): string {
    return $handler->handle('a'); // ImpureMethodCall: The context is pure but method Handler::handle requires impure
}
```

With a function-level template, the closures passed in decide the purity:

```php
<?php
/**
 * @psalm-pure
 * @psalm-purity-template P
 * @param Closure[P](int): int $callback
 * @psalm-purity-from-template P
 */
function apply(Closure $callback): int {
    return $callback(1);
}

/** @psalm-pure */
function usePure(): int {
    return apply(fn(int $x): int => $x + 1); // fine: the closure is pure
}

/** @psalm-capabilities io */
function useIo(): int {
    return apply(function (int $x): int { echo $x; return $x; }); // fine: the call costs io
}

/** @psalm-pure */
function usePrinting(): int {
    return apply(function (int $x): int { echo $x; return $x; }); // ImpureFunctionCall: The context is pure but function call on apply requires io
}
```

A type template bound to a closure type carries the closure's purity, so it works with
`@psalm-purity-from-template` too:

```php
<?php
/**
 * @template T of callable(): void
 */
final class Deferred {
    /** @var T */
    private $callback;

    /**
     * @param T $callback
     * @psalm-capabilities write-this-props
     */
    public function __construct($callback) {
        $this->callback = $callback;
    }

    /**
     * @psalm-capabilities read-props
     * @psalm-purity-from-template T
     */
    public function run(): void {
        ($this->callback)();
    }
}

/**
 * @psalm-capabilities read-props
 * @param Deferred<pure-Closure(): void> $deferred
 */
function runPure(Deferred $deferred): void {
    $deferred->run(); // fine: T is a pure closure
}
```

### The `_` shorthand

The common case, a function whose purity follows one closure parameter, needs no named template:
`Closure[_](...)` or `callable[_](...)` in a `@param` type declares one, and the function takes
its purity from that parameter, like Hack's `(function()[_]: T) $f`. This is the same `apply()` as
above:

```php
<?php
/**
 * @psalm-pure
 * @param Closure[_](int): int $callback
 */
function apply(Closure $callback): int {
    return $callback(1);
}
```

`_` may appear anywhere in a parameter's type (`list<Closure[_](int): int>`,
`Traversable[_]<int, string>`). Every `_` in one parameter's type stands for the same template,
which has no name of its own, so it never clashes with a template declared in the docblock. `_`
can only be used in `@param` types: in `@return`, `@param-out`, `@psalm-assert`, `@var`,
`@property` or `@template` bounds it has no parameter to stand for.

On a promoted constructor parameter, `_` makes `new` take the purity of the closure passed for
it, as for any other parameter. The property, though, outlives that call, so its type uses the
template's bound: here `$f` is an `impure-Closure(): int`, and calling it needs every capability,
whatever closure was passed.

```php
<?php
final class Holder {
    /**
     * @psalm-pure
     * @param Closure[_](): int $f
     */
    public function __construct(public Closure $f) {}
}
```

To keep the closure's purity in the property, use a class purity template instead
(`@psalm-purity-template P` on the class, `@param Closure[P](): int $f` on the constructor): then
`new Holder(fn(): int => 1)` is a `Holder[pure]`, whose `$f` is a pure closure.

The parameters of an `@method` may use `_` too. A call to such a method needs what `__call` (or
`__callStatic`) needs, plus the capabilities of the closures passed for its `_` parameters:

```php
<?php
/**
 * @method int run(Closure[_](): int $callback)
 */
final class Runner {
    /** @psalm-pure */
    public function __call(string $name, array $args): int { return 1; }
}

/** @psalm-pure */
function usePure(Runner $runner): int {
    return $runner->run(fn(): int => 1); // fine: the closure is pure
}
```

### Defaults and bounds

The bounds of a purity template are written as a chain, `lower <= Name(default) <= upper`, where
every part but the name is optional:

- the upper bound is the most a value may need (`impure` when left out): `P <= write-props|io`;
- on a class, the lower bound is what every value needs, which the methods depending on the
  template may then use unconditionally: `write-this-props <= C`;
- the default, in parentheses, applies to subclasses that don't bind the template: `C(pure)`.

Several templates can be declared in one tag, separated by commas (`P <= io, Q`). In a chain with
a single bound, the side that is a capability is the bound: `io <= C` is a lower bound and
`C <= io` an upper bound. A type alias used as a lower bound needs the upper bound written out
as well (`Alias <= C <= impure`). In Hack these are the bounds and default of a context
constant, with the keywords reversed as contexts are types:
`abstract const ctx C super [write_props, io] as [write_this_props] = [write_this_props]`.

A binding must include the lower bound itself: `Doer[io]` is rejected, write `Doer[write-this-props|io]`.

```php
<?php
/** @psalm-purity-template write-this-props <= C(write-this-props) <= write-this-props|write-props|io */
abstract class Doer {
    public int $runs = 0;

    /**
     * @psalm-capabilities read-props
     * @psalm-purity-from-template C
     */
    public function run(): int {
        $this->runs++; // fine: every C includes write-this-props
        return $this->runs;
    }
}

/** @extends Doer[write-this-props|io] */
final class LoudDoer extends Doer {} // fine: between the bounds

/** @extends Doer[write-globals] */
final class GlobalDoer extends Doer {} // InvalidTemplateParam: Extended template param C expects type write-this-props|write-props|io, type write-globals given

/** @extends Doer[pure] */
final class PureDoer extends Doer {} // InvalidTemplateParam: Extended template param C must include at least write-this-props, pure given

final class DefaultDoer extends Doer {} // C is write-this-props
```

### Constructors

A constructor may take its purity from a class purity template. `new Sub()` then costs what `Sub`
binds the template to, or its default or upper bound when `Sub` doesn't bind it, and
`new static()` costs the template itself, as it may instantiate any class extending the class.

`new` can also bind a class purity template from what the constructor is given. A parameter
typed `Closure[P]` binds it from the purity of a closure. To bind it from the *kind* of argument
instead, give the constructor a `@return`: the type of the `new` expression, which is the class
itself with its template and purity arguments. Like any return type, it may be conditional.
`ArrayObject` and `ArrayIterator` are declared this way: their mutators only write the object
itself when it stores an array, but also write the object it wraps when given one. A class like
them can say so:

```php
<?php
/**
 * @template TValue
 * @psalm-purity-template TStorage(write-props) <= write-props
 * @psalm-capabilities read-props|write-this-props
 */
final class Store {
    private int $writes = 0;

    /**
     * @param array<TValue>|object $storage
     * @return ($storage is array ? Store[pure]<TValue> : Store[write-props]<TValue>)
     * @psalm-pure
     */
    public function __construct(array|object $storage = []) {}

    /**
     * @param TValue $value
     * @psalm-purity-from-template TStorage
     */
    public function add($value): void {
        $this->writes++;
    }
}

/** @psalm-pure */
function fromArray(): int {
    $store = new Store([1]); // Store[pure]<int>
    $store->add(2); // fine: TStorage is pure, and $store was created here
    return 1;
}

/** @psalm-pure */
function fromObject(stdClass $object): int {
    $store = new Store($object); // Store[write-props]<mixed>
    $store->add(1); // ImpureMethodCall: The context is pure but method Store::add requires write-props
    return 1;
}
```

An argument that may be either an array or an object gives the union of both types, so calling
`add()` on the result costs `write-props`. A `@return` without a condition binds type templates
the same way: with `@return Box<int>` on its constructor, `new Box()` is a `Box<int>`.

A condition can also be given to each purity argument, inside the brackets, and a branch may be a
purity template of the constructor, bound from the argument. With
`@param array<K, V>|Container[PP]<K, V> $param` and `@return self[$param is array ? pure : PP]<K, V>`,
`new Wrapper($container)` takes the purity argument of `$container`, `io` for a
`Container[io]<string, int>`. Such conditional purity arguments are resolved per call in the
`@return` of any function or method, also nested (`list<Box[$x is array ? pure : io]<int>>`), and in
`@psalm-self-out`.

The `@return` of a constructor may only name its own class (or `self` or `static`); anything else
is an `InvalidDocblock`. Since it names the class itself, a subclass inheriting the constructor,
and `new static()` in a class that isn't final, get the type `new` would give without it.

### Iterators and generators

`Traversable`, `Iterator`, `IteratorAggregate` and `Generator` have a purity template besides
their key and value templates, `TPurity`: what iterating over them may do.
`Iterator[pure]<int, string>` can be iterated by a pure function, and
`Generator[io]<int, int, mixed, void>` prints when consumed. It defaults to `impure`, so
`Iterator<int, string>` still means an iterator about which nothing is known.

Iterating over a value known only by one of these types costs its `TPurity` and nothing else: a
pure function may consume any `Iterator[pure]<int, string>` or
`Generator[pure]<int, int, mixed, mixed>`, including one it was given (where a generator is
paused is internal engine state). Iterating over an object of an iterator class calls that
class's own methods (`rewind`, `valid`, `current`, `key`, `next`, or `getIterator()` and then the
methods of the iterator it returns, which counts as new), so it costs what they need like any
other [method call](#method-calls).

`iterable` has a purity too: `iterable[pure]<int, string>` accepts arrays (iterating over an array
does nothing) and `Traversable[pure]<int, string>`, and a pure function may iterate over it. A
plain `iterable<int, string>` is `iterable[impure]<int, string>`, since it may be any
`Traversable`. The purity of an `iterable` parameter may be a purity template
(`iterable[P]<int, string>`), bound by each call to what iterating over the argument does.

A generator function-like with a purity annotation binds the `TPurity` of the `Generator` (or
`Iterator`, `Traversable`) it returns, or the purity of the `iterable` it returns, to its own
capabilities and purity templates, which every call resolves: consuming the generator costs what
running its body costs.

```php
<?php
/**
 * @psalm-pure
 * @param Closure[_](): int $f
 * @return Generator<int, int>
 */
function map(Closure $f): Generator { yield $f(); return 0; }

/** @psalm-pure */
function sum(): int {
    $total = 0;
    foreach (map(fn(): int => 1) as $x) { // fine: a Generator[pure]<int, int, mixed, mixed>
        $total += $x;
    }
    return $total;
}

/**
 * @psalm-pure
 * @param Generator[io]<int, int> $generator for example map(function (): int { echo "x"; return 1; })
 */
function printAll(Generator $generator): int {
    foreach ($generator as $x) {} // ImpureMethodCall: The context is pure but iterating over Generator[io]<int, int, mixed, mixed> requires io
    return 0;
}
```

A class implementing `Iterator` or `IteratorAggregate` may bind `TPurity` in its `@implements`
(`@implements Iterator[pure]<int, string>`); its iteration methods (or its `getIterator()` and
what that returns) must then fit the binding. A class that doesn't bind it gets it from those
methods, as whoever iterates over it sees them: a method writing the iterator's own properties
makes it `write-this-props|write-props`. So `MyIterator` is accepted where
`Iterator[pure]<int, string>` is expected exactly when its iteration methods are pure.

The SPL iterators wrapping another one (`IteratorIterator`, `FilterIterator`,
`CallbackFilterIterator`, `LimitIterator`, `NoRewindIterator`, `InfiniteIterator`) have a
`TPurity` too, bound at construction to what iterating over the inner iterator (and calling the
callback of a `CallbackFilterIterator`) does: `new CallbackFilterIterator(gen(), fn(int $v): bool => $v > 0)`
is a `CallbackFilterIterator[pure]<...>` when `gen()` returns a `Generator[pure]<...>`. A subclass of
`FilterIterator` that doesn't bind `TPurity` iterates impurely, whatever its `accept()` does.

### Builtins taking callbacks

The builtins that call the closures they are given work the same way: `array_map`, `usort`,
`preg_replace_callback`, `ArrayObject::uasort`, `Ds\Vector::map`, … need what their callbacks
need and nothing else, and `iterator_to_array` and `iterator_count` what iterating over their
argument does. `Fiber` has a purity template for what its callback does, which starting or
resuming the fiber costs. `Closure::bind()` and `bindTo()` keep the type of the closure they
rebind, and `$closure->call($newThis, ...)` is a call of the closure that writes `$newThis`
where the closure writes `$this`.

## Overrides

An override may need fewer capabilities than the method it overrides, never more. This holds for
every capability, and for interface methods as well as parent class methods:

```php
<?php
/** @psalm-immutable */
interface Shape {
    /** @psalm-capabilities read-props */
    public function area(): float;
}

/** @psalm-immutable */
final class Square implements Shape {
    public function __construct(private float $side) {}

    public function area(): float { // fine: read-props, like Shape::area
        return $this->side * $this->side;
    }
}

/** @psalm-pure */
final class Unit implements Shape {
    public function area(): float { // fine: pure needs less than read-props
        return 1.0;
    }
}

// both reported on the class name:
// ImmutableDependency: Shape is marked with @psalm-immutable, but LoggedUnit is not
// ImmutableDependency: Shape::area is read-props, but LoggedUnit::area additionally requires io
/** @psalm-capabilities io */
final class LoggedUnit implements Shape {
    public function area(): float {
        echo 'area';
        return 1.0;
    }
}
```

[ImmutableDependency](../running_psalm/issues/ImmutableDependency.md) is a level 1 issue, so it is
reported as info at the default level 2.

A subclass may bind a class purity template of its parent to one of its own
(`@psalm-purity-template P` with `@extends Filter[P]`), which each `new` then binds, possibly to
`pure`. So an override of a method with `@psalm-purity-from-template` may use the template only as
the parent does: what it needs unconditionally must fit what the parent's method needs
unconditionally, plus the template's lower bound. This is like overrides in Hack, which may only
use an abstract context constant through `this::C`.

## Property refinements after calls

By default Psalm remembers what it knows about object properties across calls. With
[`rememberPropertyAssignmentsAfterCall="false"`](../running_psalm/configuration.md#rememberpropertyassignmentsaftercall),
it forgets refinements after a call, but only those the call could invalidate:

| The callee may use                | Psalm forgets refinements of                      |
|-----------------------------------|---------------------------------------------------|
| `write-this-props` or `write-props` | properties of mutable objects                   |
| `write-globals`                   | static properties and superglobals                |
| none of these                     | nothing                                           |

This applies to function calls, method calls, static calls and `new`. With
`rememberPropertyAssignmentsAfterCall="false"`, this code reports one issue:

```php
<?php
final class Order {
    public ?int $total = null;
    public static ?string $currency = null;
}

/** @psalm-capabilities read-globals */
function currencyIsSet(): bool {
    return Order::$currency !== null;
}

/** @psalm-capabilities write-props */
function clear(Order $order): void {
    $order->total = null;
}

function kept(Order $order): int {
    if ($order->total === null) {
        return 0;
    }
    currencyIsSet();
    return $order->total; // fine: currencyIsSet() can't write properties
}

function forgotten(Order $order, Order $other): int {
    if ($order->total === null) {
        return 0;
    }
    clear($other);
    return $order->total; // NullableReturnStatement: clear() may have written $order->total
}
```

## Inferring annotations

Psalm infers the capabilities of unannotated code from its body and the callees it uses. It does
so as a fixpoint over the call graph, after the whole codebase has been analysed: a function-like
that only calls pure function-likes, annotated or inferred, is pure itself, whatever the order in
which they are declared, and mutual recursion, recursive closures and closures assigned to a
variable are handled. It reports code that could be annotated:

- [MissingPureAnnotation](../running_psalm/issues/MissingPureAnnotation.md): a function or method
  that could have `@psalm-pure` or `@psalm-capabilities`;
- [MissingImmutableAnnotation](../running_psalm/issues/MissingImmutableAnnotation.md): a class
  that could have `@psalm-pure`, `@psalm-immutable` or `@psalm-capabilities`;
- [MissingAbstractPureAnnotation](../running_psalm/issues/MissingAbstractPureAnnotation.md): an
  abstract method with no annotation;
- [MissingInterfaceImmutableAnnotation](../running_psalm/issues/MissingInterfaceImmutableAnnotation.md):
  an interface with no annotation.

The first two can be fixed automatically:

```bash
vendor/bin/psalm --alter --issues=MissingPureAnnotation,MissingImmutableAnnotation
```

Given this code:

```php
<?php
function slug(string $title): string { // MissingPureAnnotation: slug must be marked @psalm-pure to aid security analysis, run with --alter --issues=MissingPureAnnotation to fix this
    return strtolower(trim($title));
}

final class Cart { // MissingImmutableAnnotation: Cart must be marked @psalm-capabilities read-props|write-this-props|write-refs to aid security analysis, run with --alter --issues=MissingImmutableAnnotation to fix this
    private int $items = 0;

    public function addItem(): void { // MissingPureAnnotation: addItem must be marked @psalm-capabilities read-props|write-this-props|write-refs to aid security analysis, run with --alter --issues=MissingPureAnnotation to fix this
        $this->items++;
    }

    public function count(): int {
        return $this->items;
    }
}
```

`--alter` adds `@psalm-pure` to `slug()`, and `@psalm-capabilities read-props|write-this-props|write-refs`
to `Cart` and `addItem()`. Suggestions use the four named levels only: `pure`, `read-props`,
`read-props|write-this-props|write-refs` and `impure` (`@psalm-immutable` for a class at
`read-props`). Write a narrower set by hand if you want one.

A [class-level contract](#class-level-contracts) binds every subclass too, so the one suggested
for a class is the smallest of these levels that allows:

- what the class's own methods need;
- the contract of its parent class;
- what each known subclass needs, or what its contract allows if it has one;
- for a class but not an interface, the upper bounds of its [purity templates](#defaults-and-bounds), up to which
  subclasses may bind them.

So an abstract base class whose subclasses do more, or a class with a purity template whose upper
bound is left as `impure`, gets no class-level suggestion. A subclass without an annotation is
suggested a contract on the next run, once its parent has one.

```php
<?php
abstract class Shape { // fine: no suggestion, as only impure covers Circle
    /** @psalm-pure */
    public function name(): string {
        return 'shape';
    }
}

final class Circle extends Shape {
    public function draw(): void {
        echo 'o';
    }
}

class Base { // MissingImmutableAnnotation: Base must be marked @psalm-capabilities read-props|write-this-props|write-refs to aid security analysis, run with --alter --issues=MissingImmutableAnnotation to fix this
    /** @psalm-pure */
    public function name(): string {
        return 'base';
    }
}

final class Child extends Base {
    private int $count = 0;

    /** @psalm-capabilities read-props|write-this-props */
    public function increment(): void {
        $this->count++;
    }
}
```

Psalm doesn't suggest an annotation for an unannotated method that is overridden somewhere, nor
for the code calling it, since the annotation would restrict its overrides. Annotate it yourself
when you want a contract. It doesn't suggest one either when the function-like's
[parameter default values](#parameter-default-values) need capabilities the annotation wouldn't
give them. A function-like marked `@psalm-impure` is never reported.

These issues are always reported as errors. To turn them off, or to adopt them gradually, use
`issueHandlers`:

```xml
<issueHandlers>
    <MissingPureAnnotation errorLevel="suppress" />
    <MissingImmutableAnnotation errorLevel="suppress" />
    <MissingAbstractPureAnnotation errorLevel="suppress" />
    <MissingInterfaceImmutableAnnotation errorLevel="suppress" />
</issueHandlers>
```

## Migrating from Psalm 6

Existing annotations keep their meaning:

- `@psalm-pure` and `@psalm-immutable` are unchanged.
- `@psalm-mutation-free` means `@psalm-capabilities read-props`.
- `@psalm-external-mutation-free` means `@psalm-capabilities read-props|write-this-props|write-refs`.
  It no longer allows static properties or `static` variables: use `read-globals` or
  `write-globals` for those.

`@psalm-mutation-free` and `@psalm-external-mutation-free` are still accepted but no longer
documented or suggested. `mutation-free` and `external-mutation-free` are not capability names,
so `@psalm-capabilities mutation-free` is an `InvalidDocblock`.

What changes for your code:

- **Calls on objects of the same class are no longer free.** In Psalm 6, a method could call a
  mutating method on any object of its own class, and a `@psalm-mutation-free` method could call
  one on `$this`. Now a call on `$this` costs `write-this-props` and a call on any other object
  costs `write-props` (see [Method calls](#method-calls)).
- **Overrides are checked at every level.** Psalm 6 only reported impure overrides of
  `@psalm-external-mutation-free` methods. Now any override that needs more capabilities is
  reported, as `ImmutableDependency`.
- **`MissingImmutableAnnotation` has a new meaning.** In Psalm 6 it reported a mutable class
  inheriting from an immutable one; that is now `ImmutableDependency`. `MissingImmutableAnnotation`
  now reports a class that *could* be annotated. Review existing suppressions of it.
- **New issues are reported by default:** `MissingPureAnnotation`, `MissingImmutableAnnotation`,
  `MissingAbstractPureAnnotation` and `MissingInterfaceImmutableAnnotation`. Run `--alter` once,
  or suppress them (see [Inferring annotations](#inferring-annotations)).
- **More is checked.** Implicit calls (`__toString`, `__clone`, `__invoke`, `ArrayAccess`,
  destructors), `throw new`, `new $className` and `call_user_func` are now checked for purity.
  Builtins with side effects need specific capabilities: `io` for I/O and random numbers,
  `time` for reading the clock, `write-globals` for process-wide state such as `mt_rand()` or `ini_set()`.
- **Iteration has a purity.** `foreach` over an object costs the iterator's methods, or the
  `TPurity` of `Traversable`, `Iterator`, `Generator` and `iterable`, instead of always being
  impure (see [Iterators and generators](#iterators-and-generators)).
- **Callable types:** `pure-callable` and `pure-Closure` still work, and any capability set can
  now be written, as in `Closure[io](int): void`. The capability names (`pure`, `impure`,
  `read-props`, …) are now reserved type names.

The full list of changes is in
[UPGRADING.md](https://github.com/vimeo/psalm/blob/master/UPGRADING.md).

---

### Annotating Code Supported Annotations (`docs/annotating_code/supported_annotations.md`)

# Supported docblock annotations

Psalm supports a wide range of docblock annotations.

## PHPDoc tags

Psalm uses the following PHPDoc tags to understand your code:

- [`@var`](https://docs.phpdoc.org/guide/references/phpdoc/tags/var.html)
  Used for specifying the types of properties and variables
- [`@return`](https://docs.phpdoc.org/guide/references/phpdoc/tags/return.html)
  Used for specifying the return types of functions, methods and closures. On a constructor, it
  gives the type of the object `new` creates (see [Constructors](purity_model.md#constructors))
- [`@param`](https://docs.phpdoc.org/guide/references/phpdoc/tags/param.html)
  Used for specifying types of parameters passed to functions, methods and closures
- [`@property`](https://docs.phpdoc.org/guide/references/phpdoc/tags/property.html)
  Used to specify what properties can be accessed on an object that uses `__get` and `__set`
- [`@property-read`](https://docs.phpdoc.org/guide/references/phpdoc/tags/property.html)
  Used to specify what properties can be read on object that uses `__get`
- [`@property-write`](https://docs.phpdoc.org/guide/references/phpdoc/tags/property.html)
  Used to specify what properties can be written on object that uses `__set`
- [`@method`](https://docs.phpdoc.org/guide/references/phpdoc/tags/method.html)
  Used to specify which magic methods are available on object that uses `__call`.
- [`@deprecated`](https://docs.phpdoc.org/guide/references/phpdoc/tags/deprecated.html)
  Used to mark functions, methods, classes and interfaces as being deprecated
- [`@internal`](https://docs.phpdoc.org/guide/references/phpdoc/tags/internal.html)
   Used to mark classes, functions and properties that are internal to an application or library.
- [`@mixin`](#mixins)
    Used to tell Psalm that the current class proxies the methods and properties of the referenced class.

### Off-label usage of the `@var` tag

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`.

```php
<?php
/** @var string */
$a = $_GET['foo'];

/** @var string $b */
$b = $_GET['bar'];

function bat(): string {
    /** @var string */
    return $_GET['bat'];
}
```
### @mixins

Adding `@mixin` to a classes docblock tells Psalm that the class proxies will proxy the methods and properties of the referenced class.

```php
class A
{
    public string $a = 'A';
 
    public function doA(): void
    {
    }
}

/**
 * @mixin A
 */
class B
{
    public string $b = 'B';

    public function doB(): void
    {
    }

    public function __call($name, $arguments)
    {
        (new A())->$name(...$arguments);
    }
    
    public function __get($name)
    {
        (new A())->$name;
    }
}

$b = new B();
$b->doB();
$b->doA(); // works
echo $b->b;
echo $b->a; // works
```

Mixins are followed transitively: if `B` mixes in `A` and `C` mixes in `B`, members of `A` are also available on `C`.
Chains are only followed through non-generic mixins; a generic hop such as `@mixin Collection<T>` is not traversed.


## Psalm-specific tags

There are a number of custom tags that determine how Psalm treats your code.

### `@psalm-consistent-constructor`

See [UnsafeInstantiation](../running_psalm/issues/UnsafeInstantiation.md)

### `@psalm-consistent-templates`

See [UnsafeGenericInstantiation](../running_psalm/issues/UnsafeGenericInstantiation.md)

### `@param-out`, `@psalm-param-out`

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.

```php
<?php
/**
 * @param-out string $s
 */
function addFoo(?string &$s) : void {
    if ($s === null) {
        $s = "hello";
    }
    $s .= "foo";
}
```

### `@param-closure-this`, `@psalm-param-closure-this`, `@phpstan-param-closure-this`

This binds `$this` to a specific class type inside a `Closure` or arrow-function expression passed directly as an argument. Use it when the receiving function or method runs the callback with `Closure::bind` / `Closure::call` so that `$this` resolves to a different object than the caller's `$this`. The bound type may be a class name (including a generic type such as `Box<int>`), `$this`, `static`, `self`, `parent`, or a class-level template parameter.

```php
<?php
class Macroable {
    /**
     * @param-closure-this static $macro
     */
    public static function macro(string $name, Closure $macro): void {
        // store $macro and later run $macro->call($instance)
    }
}

class Builder extends Macroable {
    public int $value = 42;
}

Builder::macro('grab', function (): int {
    // $this is Builder here, not the outer scope
    return $this->value;
});
```

Inside the callback, class scope follows the bound type: `self::` refers to that class and `parent::` to its parent. Property types retain the bound class's generic arguments rather than using the caller's property types.

The tag is ignored when it cannot name one known class to bind to (a union such as `A|B`, or a class Psalm has not seen), and when the argument is a static closure, since PHP cannot rebind one.

### `@psalm-var`, `@psalm-param`, `@psalm-return`, `@psalm-property`, `@psalm-property-read`, `@psalm-property-write`, `@psalm-method`

When specifying types in a format not supported by phpDocumentor ([but supported by Psalm](#type-syntax)) 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.

### `@psalm-ignore-var`

This annotation is used to ignore the `@var` annotation written in the same docblock. Some IDEs don't fully understand complex types like generics. To take advantage of such IDE's auto-completion, you may sometimes want to use explicit `@var` annotations even when psalm can infer the type just fine. This weakens the effectiveness of type checking in many cases since the explicit `@var` annotation overrides the types inferred by psalm. As psalm ignores the `@var` annotation which is co-located with `@psalm-ignore-var`, IDEs can use the type specified by the `@var` for auto-completion, while psalm can still use its own inferred type for type checking.

```php
<?php
/** @return iterable<array-key,\DateTime> $f */
function getTimes(int $n): iterable {
    while ($n--) {
        yield new \DateTime();
    }
};
/**
 * @var \Datetime[] $times
 * @psalm-ignore-var
 */
$times = getTimes(3);
// this trace shows "iterable<array-key, DateTime>" instead of "array<array-key, Datetime>"
/** @psalm-trace $times */
foreach ($times as $time) {
    echo $time->format('Y-m-d H:i:s.u') . PHP_EOL;
}
```

### `@psalm-suppress SomeIssueName`

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:

```php
<?php
/**
 * @psalm-suppress PossiblyNullOperand
 */
function addString(?string $s) {
    echo "hello " . $s;
}
```

Inline example:

```php
<?php
function addString(?string $s) {
    /** @psalm-suppress PossiblyNullOperand */
    echo "hello " . $s;
}
```

`@psalm-suppress all` can be used to suppress all issues instead of listing them individually.

Suppressing an unused-code issue (such as `UnusedClass` or `PossiblyUnusedMethod`) only silences the report for that symbol — it does not mark the symbol as used, so code that is only referenced from it is still reported as unused. Redundant `@psalm-suppress` annotations, in any docblock (including on classes, interfaces, traits and enums), are reported by [`--find-unused-psalm-suppress`](../running_psalm/issues/UnusedPsalmSuppress.md).

### `@psalm-assert`, `@psalm-assert-if-true`, `@psalm-assert-if-false`, `@psalm-if-this-is` and `@psalm-this-out`

See [Adding assertions](adding_assertions.md).

### `@psalm-ignore-nullable-return`

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.

```php
<?php
class Foo {}
function takesFoo(Foo $f): void {}

/** @psalm-ignore-nullable-return */
function getFoo(): ?Foo {
  return rand(0, 10000) > 1 ? new Foo() : null;
}

takesFoo(getFoo());
```

### `@psalm-ignore-falsable-return`

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.

### `@psalm-seal-properties`, `@psalm-no-seal-properties`, `@seal-properties`, `@no-seal-properties`

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.
This is automatically enabled with the configuration option `sealAllProperties` and can be disabled for a class with `@psalm-no-seal-properties`

```php
<?php
/**
 * @property string $foo
 * @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
```

### `@psalm-seal-methods`, `@psalm-no-seal-methods`, `@seal-methods`, `@no-seal-methods`

If you have a magic method caller, you can use `@psalm-seal-methods` to instruct Psalm to disallow calling any methods not contained in a list of `@method` annotations.
This is automatically enabled with the configuration option `sealAllMethods` and can be disabled for a class with `@psalm-no-seal-methods`

```php
<?php
/**
 * @method foo(): string
 * @seal-methods
 */
class A {
     public function __call(string $name, array $args) {
          if ($name === "foo") {
               return "hello";
          }
     }
 }

$a = new A();
$b = $a->bar(); // this call fails
```

### `@psalm-internal`

Used to mark a class, property or function as internal to a given namespace or class or even method. 
Psalm treats this slightly differently to the PHPDoc `@internal` tag. For `@internal`,
an issue is raised if the calling code is in a namespace completely unrelated to the namespace of the calling code,
i.e. not sharing the first element of the namespace.

In contrast for `@psalm-internal`, the docblock line must specify a namespace. An issue is raised if the calling code
is not within the given namespace.

```php
<?php
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 {
    class B {
        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
        }
    }
}

namespace X {
    class Foo {        
        /**
         * @psalm-internal Y\Bat::batBat
         */
        public static function barBar(): void {
        }
    }
}

namespace Y {
    class Bat {
        public function batBat() : void {
            \X\Foo::barBar(); // this is fine
        }
        public function fooFoo(): void {
            \X\Foo::barBar(); // error
        }
    }
}
```

### `@psalm-readonly` and `@readonly`

Used to annotate a property that can only be written to in its defining class's constructor.

```php
<?php
class B {
  /** @readonly */
  public string $s;

  public function __construct(string $s) {
    $this->s = $s;
  }
}

$b = new B("hello");
echo $b->s;
$b->s = "boo"; // disallowed
```

### Purity and capabilities

Psalm tracks the side effects a function, method or closure may have as a set of capabilities:
`read-props`, `write-this-props`, `write-props`, `read-globals`, `write-globals`, `write-refs`, `io`
and `time`, with `pure` for none of them and `impure` for all of them. [The Purity Model](purity_model.md)
explains what each capability allows, how calls are charged and how purity templates work. The
annotations are listed below.

### `@psalm-pure` and `@psalm-impure`

`@psalm-pure` on a function or method gives it no capabilities: its result depends only on its
arguments. On a class, it applies to every method and bans the use of properties. `@psalm-impure`
on a function or method gives it every capability, the default for unannotated code, written out.
See [Annotations](purity_model.md#annotations).

### `@psalm-capabilities`

`@psalm-capabilities <set>` on a function, method or closure gives the capabilities it may use,
separated by `|` or commas, as in `@psalm-capabilities read-props|write-this-props`. The set may be
a [type alias](purity_model.md#capability-aliases). On a class or interface, it is a
[contract](purity_model.md#class-level-contracts) for every method of the class and of the classes
extending or implementing it. See [Capabilities](purity_model.md#capabilities).

### `@psalm-immutable`

Used to annotate a class where every property is treated by consumers as `@psalm-readonly` and every instance method is treated as `@psalm-capabilities read-props` (see [Annotations](purity_model.md#annotations)).

```php
<?php
/**
 * @psalm-immutable
 */
abstract class Foo
{
    public string $baz;

    abstract public function bar(): int;
}

/**
 * @psalm-immutable
 */
final class ChildClass extends Foo
{
    public function __construct(string $baz)
    {
        $this->baz = $baz;
    }

    public function bar(): int
    {
        return 0;
    }
}

$anonymous = new /** @psalm-immutable */ class extends Foo
{
    public string $baz = "B";

    public function bar(): int
    {
        return 1;
    }
};
```

### `@psalm-mutable`

Used to annotate a class where at least one property is mutable: this is the default behavior, but it can be explicitly marked for clarity.

### `@psalm-purity-template`

`@psalm-purity-template P` on a class, function or method declares a purity template: a template
parameter whose values are capability sets rather than types. It is used as the purity of a
callable (`Closure[P](int): int`) or as the purity argument of a class (`Box[P]<int>`,
`@extends Box[pure]`). Bounds and a default are written as a chain,
`@psalm-purity-template lower <= P(default) <= upper`, and `Closure[_](...)` in a `@param` type
declares an unnamed one. See [Purity templates](purity_model.md#purity-templates).

### Iterators and generators

`Traversable`, `Iterator`, `IteratorAggregate`, `Generator` and `iterable` have a purity template,
`TPurity`: what iterating over them may do, as in `Iterator[pure]<int, string>` or
`iterable[pure]<int, string>` (`impure` by default). See
[Iterators and generators](purity_model.md#iterators-and-generators).

### `@psalm-purity-from-template`

`@psalm-purity-from-template P` on a function or method: each call needs the function-like's own
capabilities plus whatever `P`, a purity template or a type template bound to a closure type, is
bound to at that call. See
[`@psalm-purity-from-template`](purity_model.md#psalm-purity-from-template).

### `@psalm-allow-private-mutation`

Used to annotate readonly properties that can be mutated in a private context. With this, public properties can be read from another class but only be mutated within a method of its own class.

```php
<?php
class Counter {
  /**
   * @readonly
   * @psalm-allow-private-mutation
   */
  public int $count = 0;

  public function increment() : void {
    $this->count++;
  }
}

$counter = new Counter();
echo $counter->count; // outputs 0
$counter->increment(); // Method can mutate property
echo $counter->count; // outputs 1
$counter->count = 5; // This will fail, as it's mutating a property directly
```

### `@psalm-readonly-allow-private-mutation`

This is a shorthand for the property annotations `@readonly` and `@psalm-allow-private-mutation`.

```php
<?php
class Counter {
  /**
   * @psalm-readonly-allow-private-mutation
   */
  public int $count = 0;

  public function increment() : void {
    $this->count++;
  }
}

$counter = new Counter();
echo $counter->count; // outputs 0
$counter->increment(); // Method can mutate property
echo $counter->count; // outputs 1
$counter->count = 5; // This will fail, as it's mutating a property directly
```

### `@psalm-trace`

You can use this annotation to trace inferred type (applied to the *next* statement).

```php
<?php

/** @psalm-trace $username */
$username = $_GET['username']; // prints something like "test.php:4 $username: mixed"

```

*Note*: it throws [special low-level issue](../running_psalm/issues/Trace.md).
To see it, you can set the global `errorLevel` to 1, or invoke Psalm with
`--show-info=true`, but both these solutions will probably result in a lot of
output. Another solution is to selectively bump the error level of the issue,
so that you only get one more error:

```xml

<issueHandlers>
  <Trace errorLevel="error"/>
</issueHandlers>
```

### `@psalm-check-type`

You can use this annotation to ensure the inferred type matches what you expect.

```php
<?php

/** @psalm-check-type $foo = int */
$foo = 1; // No issue

/** @psalm-check-type $bar = int */
$bar = "not-an-int"; // Checked variable $bar = int does not match $bar = 'not-an-int'
```

### `@psalm-check-type-exact`

Like `@psalm-check-type`, but checks the exact type of the variable without allowing subtypes.

```php
<?php

/** @psalm-check-type-exact $foo = int */
$foo = 1; // Checked variable $foo = int does not match $foo = 1
```

### `@psalm-taint-*`

See [Security Analysis annotations](../security_analysis/annotations.md).

### `@psalm-type`

This allows you to define an alias for another type.

```php
<?php
/**
 * @psalm-type PhoneType = array{phone: string}
 */
class Phone {
    /**
     * @psalm-return PhoneType
     */
    public function toArray(): array {
        return ["phone" => "Nokia"];
    }
}
```

### `@psalm-import-type`

You can use this annotation to import a type defined with [`@psalm-type`](#psalm-type) if it was defined somewhere else.

```php
<?php
/**
 * @psalm-import-type PhoneType from Phone
 */
class User {
    /**
     * @psalm-return PhoneType
     */
    public function toArray(): array {
        return array_merge([], (new Phone())->toArray());
    }
}
```

You can also alias a type when you import it:

```php
<?php
/**
 * @psalm-import-type PhoneType from Phone as MyPhoneTypeAlias
 */
class User {
    /**
     * @psalm-return MyPhoneTypeAlias
     */
    public function toArray(): array {
        return array_merge([], (new Phone())->toArray());
    }
}
```

### `@psalm-require-extends`

The `@psalm-require-extends` annotation allows you to define the requirements that a trait imposes on the using class.

Psalm also reads the `@phpstan-require-extends` spelling. When a docblock has both, `@psalm-require-extends` is used.

```php
<?php
abstract class DatabaseModel {
  // methods, properties, etc.
}

/**
 * @psalm-require-extends DatabaseModel
 */
trait SoftDeletingTrait {
  // useful but scoped functionality, that depends on methods/properties from DatabaseModel
}


class MyModel extends DatabaseModel {
  // valid
  use SoftDeletingTrait;
}

class NormalClass {
  // triggers an error
  use SoftDeletingTrait;
}
```

### `@psalm-require-implements`

Behaves the same way as `@psalm-require-extends`, but for interfaces.

Psalm also reads the `@phpstan-require-implements` spelling. When a docblock has both, only the `@psalm-require-implements` tags are used.

### `@no-named-arguments`

This will prevent access to the function or method tagged with named parameters (by emitting a `NamedArgumentNotAllowed` issue).

Incidentally, it will change the inferred type for the following code:
```php
<?php
    function a(int ...$a){
        var_dump($a);
    }
```
The type of `$a` is `array<array-key, int>` without `@no-named-arguments` but becomes `list<int>` with it, because it excludes the case where the offset would be a string with the name of the parameter

### `@psalm-ignore-variable-property` and `@psalm-ignore-variable-method`

Instructs Psalm to ignore variable property fetch / variable method call when looking for dead code.
```php
class Foo
{
    // this property can be deleted by Psalter,
    // as potential reference in get() is ignored
    public string $bar = 'bar';

    public function get(string $name): mixed
    {
        /** @psalm-ignore-variable-property */
        return $this->{$name};
    }
}
```
When Psalm encounters variable property, it treats all properties in given class as potentially referenced.
With `@psalm-ignore-variable-property` annotation, this reference is ignored.

While `PossiblyUnusedProperty` would be emitted in both cases, using `@psalm-ignore-variable-property`
would allow [Psalter](../manipulating_code/fixing.md) to delete `Foo::$bar`.

`@psalm-ignore-variable-method` behaves the same way, but for variable method calls.

### `@psalm-yield`

Used to specify the type of value which will be sent back to a generator when an annotated object instance is yielded.

```php
<?php
/**
 * @template-covariant TValue
 * @psalm-yield TValue
 */
interface Promise {}

/**
 * @template-covariant TValue
 * @template-implements Promise<TValue>
 */
class Success implements Promise {
    /**
     * @psalm-param TValue $value
     */
    public function __construct($value) {}
}

/**
 * @return Promise<string>
 */
function fetch(): Promise {
    return new Success('{"data":[]}');
}

function (): Generator {
    $data = yield fetch();
    
    // this is fine, Psalm knows that $data is a string
    return json_decode($data);
};
```
This annotation supports only generic types, meaning that e.g. `@psalm-yield string` would be ignored.

### `@api`, `@psalm-api`

Used to tell Psalm that a class or method is used, even if no references to it can be
found. Unused issues will be suppressed.

For example, in frameworks, controllers are often invoked "magically" without
any explicit references to them in your code. You should mark these classes with
`@psalm-api`.
```php
/**
 * @psalm-api
 */
class UnreferencedClass {}
```

When an [`Unused*` issue](../running_psalm/issues.md) is reported, there are only
two correct fix paths:

 * The symbol is genuinely **public surface** — consumed from outside the
   analysed codebase, e.g. a library entry point, or a class instantiated only
   by a framework, container or plugin loader. Mark it with `@api`/`@psalm-api`.
   Use this *only* for real public surface.
 * Otherwise the symbol is **dead code** — remove it, along with anything that
   was only reachable through it.

For a reported method or property, `@api` may be placed either on that member or
on the whole class, but marking the **whole class** is almost always the right
choice: an externally-consumed member belongs to an externally-consumed class,
and one class-level annotation then covers its entire public API. Conversely, if
a member is reported as unused inside a class that is *not* marked `@api`, it is
almost always genuinely dead code — remove it rather than annotating the lone
member. Annotating an individual member is only correct in the uncommon case
where the class is not public API but that one member genuinely is.

A class that implements an interface (or extends a class) defined outside the
project is treated as public surface automatically, since it can be instantiated
and invoked through that external type: its overriding methods are considered
used without an explicit `@api`.

Do not reach for `@psalm-suppress UnusedClass` (or another `Unused*`
suppression) in place of `@api`: as noted above, a suppression only silences the
report, it does not mark the symbol as used, so symbols it references may still
be reported as unused.

### `@psalm-inheritors`

Used to tell Psalm that a class can only be extended by a certain subset of classes.

For example, 
```php
<?php
/**
 * @psalm-inheritors FooClass|BarClass
 */
class BaseClass {}
class FooClass extends BaseClass {}
class BarClass extends BaseClass {}
class BazClass extends BaseClass {} // this is an error
```

## Type Syntax

Psalm supports PHPDoc’s [type syntax](https://docs.phpdoc.org/guide/guides/types.html), and also the [proposed PHPDoc PSR type syntax](https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md#appendix-a-types).

A detailed write-up is found in [Typing in Psalm](typing_in_psalm.md)

---

### Annotating Code Templated Annotations (`docs/annotating_code/templated_annotations.md`)

# Templating

Docblocks allow you to tell Psalm some simple information about how your code works. For example `@return int` in a function return type tells Psalm that a function should return an `int` and `@return MyContainer` tells Psalm that a function should return an instance of a user-defined class `MyContainer`. In either case, Psalm can check that the function actually returns those types _and_ that anything calling that function uses its returned value properly.

Templated types allow you to tell Psalm even more information about how your code works.

Let's look at a simple class `MyContainer`:

```php
<?php
class MyContainer {
  private $value;

  public function __construct($value) {
    $this->value = $value;
  }

  public function getValue() {
    return $this->value;
  }
}
```

When Psalm handles the return type of `$my_container->getValue()` it doesn't know what it's getting out, because the value can be arbitrary.

Templated annotations provide us with a workaround - we can define a generic/templated param `T` that is a placeholder for the value inside `MyContainer`:

```php
<?php
/**
 * @template T
 */
class MyContainer {
  /** @var T */
  private $value;

  /** @param T $value */
  public function __construct($value) {
    $this->value = $value;
  }

  /** @return T */
  public function getValue() {
    return $this->value;
  }
}
```

Now we can substitute values for that templated param when we reference `MyContainer` in docblocks e.g. `@return MyContainer<int>`. This tells Psalm to substitute `T` for `int` when evaluating that return type, effectively treating it as a class that looks like

```php
<?php
class One_off_instance_of_MyContainer {
  /** @var int */
  private $value;

  /** @param int $value */
  public function __construct($value) {
    $this->value = $value;
  }

  /** @return int */
  public function getValue() {
    return $this->value;
  }
}
```

This pattern can be used in a large number of different situations like mocking, collections, iterators and loading arbitrary objects. Psalm has a large number of annotations to make it easy to use templated types in your codebase.

## `@template`, `@psalm-template`

The `@template`/`@psalm-template` tag allows classes and functions to declare a generic type parameter.

As a very simple example, this function returns whatever is passed in:

```php
<?php
/**
 * @template T
 * @psalm-param T $t
 * @return T
 */
function mirror($t) {
    return $t;
}

$a = 5;
$b = mirror($a); // Psalm knows the result is an int

$c = "foo";
$d = mirror($c); // Psalm knows the result is string
```

Psalm also uses `@template` annotations in its stubbed versions of PHP array functions e.g.

```php
<?php
/**
 * Takes one array with keys and another with values and combines them
 *
 * @template TKey
 * @template TValue
 *
 * @param array<mixed, TKey> $arr
 * @param array<mixed, TValue> $arr2
 * @return array<TKey, TValue>
 */
function array_combine(array $arr, array $arr2) {}
```

### Notes
- `@template` tag order matters for class docblocks, as they dictate the order in which those generic parameters are referenced in docblocks.
- The names of your templated types (e.g. `TKey`, `TValue`) don't matter outside the scope of the class or function in which they're declared.

## @param class-string&lt;T&gt;

Psalm also allows you to parameterize class types

```php
<?php
/**
 * @template T of Foo
 * @psalm-param class-string<T> $class
 * @return T
 */
function instantiator(string $class) {
    return new $class();
}

class Foo {
    public final function __construct() {}
}

class FooChild extends Foo {}

$r = instantiator(FooChild::class);
// Psalm knows $r is an object of type FooChild
```

## Template inheritance

Psalm allows you to extend templated classes with `@extends`/`@template-extends`:

```php
<?php
/**
 * @template T
 */
class ParentClass {}

/**
 * @extends ParentClass<int>
 */
class ChildClass extends ParentClass {}
```

similarly you can implement interfaces with `@implements`/`@template-implements`

```php
<?php
/**
 * @template T
 */
interface IFoo {}

/**
 * @implements IFoo<int>
 */
class Foo implements IFoo {}
```

and import traits with `@use`/`@template-use`

```php
<?php
/**
 * @template T
 */
trait MyTrait {}

class Foo {
    /**
     * @use MyTrait<int>
     */
    use MyTrait;
}
```

You can also extend one templated class with another, e.g.

```php
<?php
/**
 * @template T1
 */
class ParentClass {}

/**
 * @template T2
 * @extends ParentClass<T2>
 */
class ChildClass extends ParentClass {}
```

## Template constraints

You can use `@template of <type>` to restrict input. For example, to restrict to a given class you can use

```php
<?php
class Foo {}
class FooChild extends Foo {}

/**
 * @template T of Foo
 * @psalm-param T $t
 * @return array<int, T>
 */
function makeArray($t) {
    return [$t];
}
$a = makeArray(new Foo()); // typed as array<int, Foo>
$b = makeArray(new FooChild()); // typed as array<int, FooChild>
$c = makeArray(new stdClass()); // type error
```

Templated types aren't limited to key-value pairs, and you can re-use templates across multiple arguments of a template-supporting type:
```php
<?php
/**
 * @template T0 of array-key
 *
 * @template-implements IteratorAggregate<T0, int>
 */
abstract class Foo implements IteratorAggregate {
  /**
   * @var int
   */
  protected $rand_min;

  /**
   * @var int
   */
  protected $rand_max;

  public function __construct(int $rand_min, int $rand_max) {
    $this->rand_min = $rand_min;
    $this->rand_max = $rand_max;
  }

  /**
   * @return Generator<T0, int, mixed, T0>
   */
  public function getIterator() : Generator {
    $j = random_int($this->rand_min, $this->rand_max);
    for($i = $this->rand_min; $i <= $j; $i += 1) {
      yield $this->getFuzzyType($i) => $i ** $i;
    }

    return $this->getFuzzyType($j);
  }

  /**
   * @return T0
   */
  abstract protected function getFuzzyType(int $i);
}

/**
 * @template-extends Foo<int>
 */
class Bar extends Foo {
  protected function getFuzzyType(int $i) : int {
    return $i;
  }
}

/**
 * @template-extends Foo<string>
 */
class Baz extends Foo {
  protected function getFuzzyType(int $i) : string {
    return static::class . '[' . $i . ']';
  }
}
```

## Template covariance

Imagine you have code like this:

```php
<?php
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

/**
 * @template T
 */
class Collection {
    /**
     * @var array<int, T>
     */
    public array $list;

    /**
     * @param array<int, T> $list
     */
    public function __construct(array $list) {
        $this->list = $list;
    }

    /**
     * @param T $t
     */
    public function add($t) : void {
        $this->list[] = $t;
    }
}

/**
 * @param Collection<Animal> $collection
 */
function addAnimal(Collection $collection) : void {
    $collection->add(new Cat());
}

/**
 * @param Collection<Dog> $dog_collection
 */
function takesDogList(Collection $dog_collection) : void {
    addAnimal($dog_collection);
}
```

That last call `addAnimal($dog_collection)` breaks the type of the collection – suddenly a collection of dogs becomes a collection of dogs _or_ cats. That is bad.

To prevent this, Psalm emits an error when calling `addAnimal($dog_collection)` saying "addAnimal expects a `Collection<Animal>`, but `Collection<Dog>` was passed". If you haven't encountered this rule before it's probably confusing to you – any function that accepted an `Animal` would be happy to accept a subtype thereof. But as we see in the example above, doing so can lead to problems.

But there are also times where it's perfectly safe to pass template param subtypes:

```php
<?php
abstract class Animal {
    abstract public function getNoise() : string;
}
class Dog extends Animal {
    public function getNoise() : string { return "woof"; }
}
class Cat extends Animal {
    public function getNoise() : string { return "miaow"; }
}

/**
 * @template T
 */
class Collection {
    /** @var array<int, T> */
    public array $list = [];
}

/**
 * @param Collection<Animal> $collection
 */
function getNoises(Collection $collection) : void {
    foreach ($collection->list as $animal) {
        echo $animal->getNoise();
    }
}

/**
 * @param Collection<Dog> $dog_collection
 */
function takesDogList(Collection $dog_collection) : void {
    getNoises($dog_collection);
}
```

Here we're not doing anything bad – we're just iterating over an array of objects. But Psalm still gives that same basic error – "getNoises expects a `Collection<Animal>`, but `Collection<Dog>` was passed".

We can tell Psalm that it's safe to pass subtypes for the templated param `T` by using the annotation `@template-covariant T` (or `@psalm-template-covariant T`):

```php
<?php
/**
 * @template-covariant T
 */
class Collection {
    /** @var array<int, T> */
    public array $list = [];
}
```

Doing this for the above example produces no errors: [https://psalm.dev/r/5254af7a8b](https://psalm.dev/r/5254af7a8b)

But `@template-covariant` doesn't get rid of _all_ errors – if you add it to the first example, you get a new error – [https://psalm.dev/r/0fcd699231](https://psalm.dev/r/0fcd699231) – complaining that you're attempting to use a covariant template parameter for function input. That’s no good, as it means you're likely altering the collection somehow (which is, again, a violation).

### But what about immutability?

Psalm has [comprehensive support for declaring functional immutability](https://psalm.dev/articles/immutability-and-beyond).

If we make sure that the class is immutable, we can declare a class with an `add` method that still takes a covariant param as input, but which does not modify the collection at all, instead returning a new one:

```php
<?php
/**
 * @template-covariant T
 * @psalm-immutable
 */
class Collection {
    /**
     * @var array<int, T>
     */
    public array $list = [];

    /**
     * @param array<int, T> $list
     */
    public function __construct(array $list) {
        $this->list = $list;
    }

    /**
     * @param T $t
     * @return Collection<T>
     */
    public function add($t) : Collection {
        return new Collection(array_merge($this->list, [$t]));
    }
}
```

This is perfectly valid, and Psalm won't complain.

## Builtin templated classes and interfaces

Psalm has support for a number of builtin classes and interfaces that you can extend/implement in your own code.

- `interface Traversable<TKey, TValue>`
- `interface ArrayAccess<TKey, TValue>`
- `interface IteratorAggregate<TKey, TValue> extends Traversable<TKey, TValue>`
- `interface Iterator<TKey, TValue> extends Traversable<TKey, TValue>`
- `interface SeekableIterator<TKey, TValue> extends Iterator<TKey, TValue>`

- `class Generator<TKey, TValue, TSend, TReturn> extends Traversable<TKey, TValue>`
- `class ArrayObject<TKey, TValue> implements IteratorAggregate<TKey, TValue>, ArrayAccess<TKey, TValue>`
- `class ArrayIterator<TKey of array-key, TValue> implements SeekableIterator<TKey, TValue>, ArrayAccess<TKey, TValue>`
- `class DOMNodeList<TNode of DOMNode> implements Traversable<int, TNode>`
- `class SplDoublyLinkedList<TValue> implements Iterator<TKey, TValue>, ArrayAccess<TKey, TValue>`
- `class SplQueue<TValue> extends SplDoublyLinkedList<TValue>`

- `abstract class FilterIterator<TKey, TValue, TIterator>`

---

### Annotating Code Type Variables (`docs/annotating_code/type_variables.md`)

# Type Variables

A type variable is a placeholder type — rendered internally as `` `_0 ``, `` `_1 ``, … —
that stands in for a class template parameter whose concrete type is not yet known. The
idea comes from the Hack typechecker's local inference: in Hack you can write
`new Vector<_>()` and let the checker solve for the type argument from how the object is
*used*. PHP has no constructor type arguments at all, so under this model **every**
templated construction site is effectively `new Foo<_>(...)`.

## How it works

When Psalm analyzes `new Foo(...)` and `Foo` has a template `T`, it mints a fresh type
variable and makes it the object's type parameter (`Foo<`_0>`). The variable starts life
with:

- **lower bounds** — whatever the constructor arguments already implied
  (`new Box(1)` seeds `` `_0 >: 1 ``); empty if nothing bound it,
- **upper bounds** — the template's declared constraint (`@template T of int|string`
  seeds `` `_0 <: int|string ``), and, when the constructor names the type exactly
  through a `class-string<T>`/`T::class` parameter, the named type as a pin
  (`new ReflectionClass(Foo::class)` pins `` `_0 = Foo ``).

From then on the variable flows through the function body, and every use *records a
constraint instead of passing judgment*: passing a value into a `T`-typed parameter adds
a lower bound; returning the object against a declared `Foo<string>` adds an equality
upper bound; arithmetic adds an `int|float` upper bound; concatenation and `echo` add
`array-key`; scalar assertions like `is_int($v)` add lower bounds. The comparator treats
a type variable as compatible with anything during these checks — the verdict is
deferred.

When the surrounding function-like (or the file's global scope) finishes analysis, all
accumulated bounds for each variable are reconciled with each other; any lower bound
that cannot satisfy an upper bound produces
[IncompatibleTypeParameters](../running_psalm/issues/IncompatibleTypeParameters.md),
reported at the position where the offending bound was recorded. The constraints
`T <: int|string, T >: int` can hold together; `T = string, T >: 1` cannot — that pair
is what makes this code report "Type 1 should be a subtype of string" *at the `new`*:

```php
<?php

/**
 * @template T of int|string
 */
class Box {
    /** @param T $t */
    public function __construct(public $t) {}
    /** @param T $item */
    public function set($item): void {
        $this->t = $item;
    }
}

/** @return Box<string> */
function bad(): Box {
    $box = new Box(1); // IncompatibleTypeParameters: Type 1 should be a subtype of string
    $box->set("two");
    return $box;
}
```

## How this differs from Psalm's previous approach

Psalm's previous model was **eager pinning**. At the construction site the template was
resolved once and frozen: to the most specific type the constructor arguments implied
(`new Box(1)` ⇒ `Box<1>`), or to its declared constraint when nothing bound it
(`new IntBox()` with `T of int` ⇒ `IntBox<int>`). Every later use was then checked
against that frozen type, argument by argument.

The practical differences:

1. **Inference direction.** Eager pinning means the constructor is the *only* place `T`
   can be learned; everything after is checking. With type variables, inference runs
   through the whole function body — a later `$box->add(5)` on an unbound `Box`
   genuinely informs what `T` is, and `$box->get()` resolves through those accumulated
   bounds instead of falling back to the constraint.

2. **Widening is legal.** Under eager pinning, `new Box(1)` pins `T = 1`, so
   `$box->set('two')` was `InvalidArgument` ("expects 1, but 'two' provided") even
   though `'two'` satisfies `T of int|string`. Under type variables the set call just
   widens `T` toward `1|'two'`, which the constraint accepts. `T` is only ever
   *required* to be something by its declared constraint, a class-string pin, or a
   context that names it (a declared return/param/property type) — not by whichever
   value happened to reach the constructor first.

3. **Where and how errors are reported.** Eager pinning reported a separate per-call
   mismatch at each offending argument, phrased against the frozen type. Reconciliation
   reports the actual contradiction between bounds, once, at the bound that cannot hold —
   so a `Box<string>` return conflicting with the constructor argument points at
   `$box = new Box(1);`, which is where the wrong value actually entered. The issue is
   its own type (`IncompatibleTypeParameters`, level 1), shown as INFO at normal error
   levels rather than a hard error.

4. **Comparisons become provisional.** Because a type variable "matches anything while
   recording a bound," any code that used a successful containment check to make a
   *decision* (negated `instanceof` narrowing, rewriting hinted closure params from an
   expected callable) treats variable-involving containments as non-definitive — they
   record evidence for reconciliation but prove nothing on their own.

## What stays the same

- Templates with a `mixed` constraint and templates with no public mutation channel
  (named only in the constructor) are never turned into type variables — there is
  nothing to check, and nothing later could constrain them — so plain `@template T`
  classes behave exactly as before.
- `SplObjectStorage` keeps its `never` special case for unbound templates.
- A type variable renders through its bounds, so inferred types still display as
  `Box<1>` or `Foo<A>` rather than `` `_0 ``.
- Callables validate against the construction-site inference with ordinary
  `InvalidArgument` messages, since a structural signature mismatch is clearer reported
  in full than deferred to reconciliation.

---

### Annotating Code Typing In Psalm (`docs/annotating_code/typing_in_psalm.md`)

# 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 in docblocks.

All docblock types are either [atomic types](type_syntax/atomic_types.md), [union types](type_syntax/union_types.md) or [intersection types](type_syntax/intersection_types.md).

Additionally, Psalm supports PHPDoc’s [type syntax](https://docs.phpdoc.org/guide/guides/types.html#supported-types), and also the [proposed PHPDoc PSR type syntax](https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md#appendix-a-types).

## Property declaration types vs Assignment typehints

You can use the `/** @var Type */` docblock to annotate both [property declarations](http://php.net/manual/en/language.oop5.properties.php) and to help Psalm understand variable assignment.

### Property declaration types

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

```php
<?php
/** @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:

```php
<?php
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:

```php
<?php
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.

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

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

```php
<?php
/** @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](https://getpsalm.org/r/9f6f1ceab6):

```php
<?php
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:

```php
<?php
/**
 * @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:

```php
<?php
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';
  }
}
```

If the class constants share a common prefix, you can specify them all using a wildcard:

```php
<?php
class A {
  const STATUS_FOO = 'foo';
  const STATUS_BAR = 'bar';
}

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

    default:
      // any other status
      return 'goodbye';
  }
}
```

---

### Contributing Adding Issues (`docs/contributing/adding_issues.md`)

# Adding a new issue type

To add a new issue type there are a number of required steps, listed below.

## Generating a new shortcode

Run `bin/max_used_shortcode.php` and note the value it printed (`$max_shortcode`)

## Create issue class

Create a class in `Psalm\Issue` namespace like this:

```php
<?php

namespace Psalm\Issue;

final class MyNewIssue extends CodeIssue 
{
    public const ERROR_LEVEL = 2;
    public const SHORTCODE = 123;
}
```

For `SHORTCODE` value use `$max_shortcode + 1`. To choose appropriate error level see [Error levels](../running_psalm/error_levels.md).

There a number of abstract classes you can extend:

* `CodeIssue` - non-specific, default issue. It's a base class for all issues.
* `ClassIssue` - issue related to a specific class (also interface, trait, enum). These issues can be suppressed for specific classes in `psalm.xml` by using `referencedClass` attribute
* `PropertyIssue` - issue related to a specific property. Can be targeted by using `referencedProperty` in `psalm.xml`
* `FunctionIssue` - issue related to a specific function. Can be suppressed with `referencedFunction` attribute.
* `ArgumentIssue` - issue related to a specific argument. Can be targeted with `referencedFunction` attribute.
* `MethodIssue` - issue related to a specific method. Can be targeted with `referencedMethod` attribute.
* `ClassConstantIssue` - issue related to a specific class constant. Can be targeted with `referencedConstant`.
* `VariableIssue` - issue for a specific variable. Targeted with `referencedVariable`

## Add a `config.xsd` entry

All issue types needs to be listed in `config.xsd`, which is used to validate `psalm.xml`. Choose appropriate `type` attribute. E.g. for issues extending `PropertyIssue` use `type="PropertyIssueHandlerType"`.

## Add a doc page for your new issue

Every issue needs to be documented. Create a markdown file in `docs/running_psalm/issues` folder. Make sure to include a snippet of code illustrating your issue. Important: snippets must use fenced php code block and must include opening PHP tag (`<?php`). The snippet must actually produce the issue you're documenting. It's checked by our test suite.

## Add links to the doc page

Add links to the doc page you created to `docs/running_psalm/error_levels.md` and `docs/running_psalm/issues.md`

## Run documentation tests

```
$ vendor/bin/phpunit tests/DocumentationTest.php
```

It will check whether you did all (or at least most) of the steps above.

## Use your new issue type in Psalm core

```php
IssueBuffer::maybeAdd(new MyNewIssue(...))
```

---

### Contributing Editing Callmaps (`docs/contributing/editing_callmaps.md`)

# Altering callmaps

## Intro

One of the first things most contributors start with is proposing changes to
callmaps.

Callmap is a data file (formatted as a PHP file returning an array) that tells
Psalm what arguments function/method takes and what it returns.

There is a partial callmap file in `dictionaries/override/CallMap.php` folder, and
a number of delta files that provide information on
how signatures changed in various PHP versions in `dictionaries/override/CallMap_*_delta.php`. 

To alter info for a function, edit the signatures in `dictionaries/override/CallMap*` (adding the function if missing, copying it from `dictionaries/autogen/CallMap_$latest.php`).  

When editing info for a function, don't forget to alter all revisions of the same function in `dictionaries/override/CallMap_*_delta.php`.

The callmap files in the `override` subfolder are then used, in conjunction with the
automatically-generated reflection callmaps in `dictionaries/autogen`, to generate the
final callmaps in `dictionaries/CallMap_*`, which are the actual callmaps in use by Psalm.

After editing an override callmap, run `bin/gen_callmap.php` to regenerate the final callmap file.

To also regenerate the base callmaps, run `bin/gen_callmap.sh`: it will use the dockerfiles in `bin/` 
to extract types from PHP and a set of extensions.  
To add types from an extension to the callmap, edit all versions of the Dockerfiles.  

## Full callmap format

The full callmap (`CallMap.php`) has function/method
names as keys and an array representing the corresponding signature as a value.

First element of that value is a return type (it also doesn't have a key), and
subsequent elements represent function/method parameters. Parameter name for an
optional parameter is postfixed with `=`, references with `&`/`&r_`/`&w_`/`&rw_`
(depending on the read/write meaning of the reference param) and 
variadic args are prefixed with `...`.

Callmaps also support function aliases: aliases are very useful to specify that
a certain function behaves differently according to the parameter types.

For example, the following aliases are currently in use in the callmap to specify 
that the `version_compare` function can be called with an `operator` parameter, 
in which case it will return a boolean; otherwise it will return an integer.  

```php
[
    'version_compare' => [
        0 => 'bool',
        'version1' => 'string',
        'version2' => 'string',
        'operator' => '\'!=\'|\'<\'|\'<=\'|\'<>\'|\'=\'|\'==\'|\'>\'|\'>=\'|\'eq\'|\'ge\'|\'gt\'|\'le\'|\'lt\'|\'ne\'|null',
    ],
    'version_compare\'1' => [
        0 => 'int',
        'version1' => 'string',
        'version2' => 'string',
    ],
]
```

**Note**: the above example doesn't provide almost any useful information for type inference;
in fact, the real logic for return type inference is contained in the `VersionCompareReturnTypeProvider`.  

The callmap is mainly useful when treating functions and methods as *callable values*, for example:

```php
<?php
function naive_version_compare(string $a, string $b, ?string $operator = null): int|bool {
    return 0;
}

$a = ["1.0", "2.0"];

// OK
usort($a, "version_compare");

// InvalidArgument: Argument 2 of usort expects callable(string, string):int, but impure-callable(string, string, null|string=):(bool|int) provided
usort($a, "naive_version_compare");
```

The first usort succeeds, because psalm chooses the correct alias to use between the two provided in the callmap.  
The second usort fails (equivalent to the non-split return type of `version_compare` inferred by reflection), because the return type is a union of the two possible signatures of version_compare.  

When you have multifaceted functions like these, it's a very good idea to at least define a templated stub in `stubs/` for them, or a custom return type provider for even more complex logic, not representable with templates/conditional types/etc in a stub.

Also note that `bin/gen_callmap.php` has some validation logic which will re-add back removed parameters in overridden aliased callmaps: to avoid this, explicitly whitelist aliased functions by editing `assertParameter` in `bin/gen_callmap_utils.php`, and eventually `bin/gen_callmap.php` as needed.

## Delta file format

Delta files (named `CallMap_<PHP major version><PHP minor version>_delta.php`)
list changes that happened in the corresponding PHP version. There are
three section with self-explanatory names: `added` (for functions/methods that
were added in that PHP version), `removed` (for those that were removed) and
`changed`.

Entry format for `removed` and `added` section matches that of a full callmap,
while `changed` entries list `old` and `new` signatures.

## How Psalm uses delta files

When the current PHP version is set to something other than the latest PHP
version supported by Psalm, it needs to process delta files to arrive at a
version of callmap matching the one that is used during analysis. Psalm uses
the following process to do that:

1. Read `CallMap.php` (Note: it's the one having the latest signatures).
2. If it matches configured PHP version, use it.
3. If the callmap delta for previous PHP version exists, read that.
4. Take previous callmap delta and apply it in reverse order. That is, entries
   in `removed` section are added, those in `added` section are removed and
   `changed.new` signatures in the current callamp are replaced with
   `changed.old`.
5. Goto 2

## Consistent histories

To make sure there are no mismatches in deltas and the callmap, CI validates
that all function/method entries have consistent histories. E.g. that the
signature in `changed.new` matches the one in `CallMap.php`, the `removed`
entries are actually absent from `CallMap.php` and so on.

## Typical changes

To put that into practical perspective, let's see how a couple of typical
callmap changes may look like.

### Adding a new function

Say, there's a function added in PHP 8.1, e.g. `array_is_list()`. Add it to the
`CallMap_81_delta.php` (as it was introduced in PHP 8.1), and `CallMap.php` (as
it exists in the latest PHP version). Here's [the PR that does it](https://github.com/vimeo/psalm/pull/6398/files).

### Correcting the function signature

Assume you found an incorrect signature, the one that was always different to what
we currently have in Psalm. This will need a change to `CallMap.php` (as the signature is
still valid). Here's [the PR that does it](https://github.com/vimeo/psalm/pull/6359/files).

If function signature is correct for an older version but has changed since you
will need to edit the delta for PHP version where signature changed and
`CallMap.php` (as this new signature is still valid).  Here's
[the PR that does it (makes `timestamp` nullable)](https://github.com/vimeo/psalm/pull/6244/files).

---

### Contributing How Psalm Works (`docs/contributing/how_psalm_works.md`)

# How Psalm works

The entry point for all analysis is [`ProjectAnalyzer`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php)

`ProjectAnalyzer` is in charge of two things: Scanning and Analysis

## Scanning

For any file or set of files, Psalm needs to determine all the possible dependencies and get their function signatures and constants, so that the analysis phase can be done multi-threaded.

Scanning happens in `Psalm\Internal\Codebase\Scanner`.

The first task is to convert a file into a set of [PHP Parser](https://github.com/nikic/PHP-Parser) statements. PHP Parser converts PHP code into an abstract syntax tree that Psalm uses for all its analysis.

### Deep scanning vs shallow scanning

Psalm then uses a custom PHP Parser `NodeVisitor` called [`ReflectorVisitor`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php) which has two modes when scanning a given file: a shallow scan, where it just gets function signatures, return types, constants, and inheritance, or a deep scan, where it drills into every function statement to get those dependencies too (e.g. the class names instantiated by a function). It only does a deep scan on files that it knows will be analysed later (so the vast majority of the vendor directory, for example, just gets a shallow scan).

So, when analysing the `src` directory, Psalm will deep scan the following file:

src/A.php
```php
<?php
use Vendor\VendorClass;
use Vendor\OtherVendorClass;

class A extends VendorClass
{
    public function foo(OtherVendorClass $c): void {}
}
```

And will also deep scan the file belonging to `Vendor\VendorClass`, because it may have to check instantiations of properties at some point.

It will do a shallow scan of `Vendor\OtherVendorClass` (and any dependents) because all it cares about are the method signatures and return types of the variable `$c`.

### Finding files from class names

To figure out the `ClassName` => `src/FileName.php` mapping it uses reflection for project files and the Composer classmap for vendor files.

### Storing data from scanning

For each file that `ReflectorVisitor` visits, Psalm creates a [`FileStorage`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Storage/FileStorage.php) instance, along with [`ClassLikeStorage`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Storage/ClassLikeStorage.php) and [`FunctionLikeStorage`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Storage/FunctionLikeStorage.php) instances depending on the file contents.

Once we have a set of all files and their classes and function signatures, we calculate inheritance for everything in the [`Populator`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Codebase/Populator.php) class and then move onto analysis.

At the end of the scanning step we have populated all the necessary information in [`ClassLikes`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Codebase/ClassLikes.php), [`Functions`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Codebase/Functions.php) and [`Methods`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Codebase/Methods.php) classes, and created a complete list of `FileStorage` and `ClassLikeStorage` objects (in [`FileStorageProvider`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Provider/FileStorageProvider.php) and [`ClassLikeStorageProvider`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php) respectively) for all classes and files used in our project.

## Analysis

We analyse files in [`FileAnalyzer`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Analyzer/FileAnalyzer.php)

The `FileAnalyzer` takes a given file and looks for a set of top-level components: classes, traits, interfaces, functions. It can look inside namespaces and extract the classes, interfaces, traits and functions in them as well.

It delegates the analysis of those components to [`ClassAnalyzer`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Analyzer/ClassAnalyzer.php), [`InterfaceAnalyzer`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Analyzer/InterfaceAnalyzer.php) and [`FunctionAnalyzer`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php).

Because it’s the most basic use case for the line-by-line analysis (no class inheritance to worry about), let’s drill down into `FunctionAnalyzer`.

### Function Analysis

`FunctionAnalyzer::analyze` is defined in [`FunctionLikeAnalyzer`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php). That method first gets the `FunctionLikeStorage` object for the given function that we created in our scanning step. That `FunctionLikeStorage` object has information about function parameters, which we then feed into a [`Context`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Context.php) object. The `Context` contains all the type information we know about variables & properties (stored in `Context::$vars_in_scope`) and also a whole bunch of other information that can change depending on assignments and assertions.

Somewhere in `FunctionLikeAnalyzer::analyze` we create a new [`StatementsAnalyzer`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php) and then call its `analyze()` method, passing in a set of PhpParser nodes. `StatementAnalyzer::analyze` passes off to a number of different checkers (`IfAnalyzer`, `ForeachAnalyzer`, `ExpressionAnalyzer` etc.) for more thorough analysis.

At each line the `Context` object may or may not be manipulated. At branching points (if statements, loops, ternary etc) the `Context` object is cloned and then, at the end of the branch, Psalm figures out how to resolve the changes and update the uncloned `Context` object.

The `NodeDataProvider` stores a type for each PhpParser node.

After all the statements have been analysed we gather up all the return types and compare them to the given return type.

### Type Reconciliation

While some updates to the `Context` object are straightforward, others are not. Updating the `Context` object in the light of new type information happens in [`Reconciler`](https://github.com/vimeo/psalm/blob/master/src/Psalm/Type/Reconciler.php), which takes an array assertions e.g. `[“$a” => “!null”]` and a list of existing type information e.g. `$a => string|null` and return a set of updated information e.g. `$a => string`

---

### Contributing Philosophy (`docs/contributing/philosophy.md`)

# Philosophy

This is about why Psalm is the way it is. This is a living document!

## Psalm is a tool for PHP written in PHP

### Advantages

- PHP is fast enough for most use-cases
- Writing the tool in PHP guarantees that PHP community members can contribute to it without too much difficulty

### Drawbacks

- Psalm is slow in very large monorepos (over 5 million lines of checked-in code).
- Psalm’s language server is more limited in what it can provide than comparable compiled-language tools. For example, it's infeasible to find/change all occurrences of a symbol, in all files that use it, as you type.

### Comparison to other languages & tools

Many languages have typecheckers/compilers written in the same language. Popular examples include Go, Rust, and TypeScript. Python is a special case where the semi-official typechecker [MyPy](https://github.com/python/mypy) (written in Python) can also [compile to a C Python extension](https://github.com/python/mypy/blame/master/mypyc/README.md#L6-L10), which runs 4x faster than the interpreted equivalent.

Some interpreted languages have unofficial open-source typecheckers written in faster compiled languages. In all cases a single mid-to-large company is behind each effort, with a small number of contributors not employed by that company:

- PHP
    - [NoVerify](https://github.com/VKCOM/noverify) – written in Go. Runs much faster than Psalm (but does not support many modern PHP features)
- Ruby
    - [Sorbet](https://sorbet.org/) - written in C
- Python
    - [Pyre](https://github.com/facebook/pyre-check) - written in OCaml
- [Hack](https://github.com/facebook/hhvm) - the typechecker is written in OCaml and Rust

## Psalm's primary purpose is finding bugs

Psalm does a lot, but people mainly use it to find potential bugs in their code.

All other functionality – the language server, security analysis, manipulating/fixing code is a secondary concern.

## It's designed to be run on syntactically-correct code

Psalm is almost always run on PHP code that parses a lint check (`php -l <filename>`) – i.e. syntactically-correct code. Psalm is not a replacement for that syntax check.

Given Psalm is almost always used on syntactically-correct code it should use a parser built for that purpose, and `nikic/php-parser` is the gold-standard.

Where Psalm needs to run on syntactically-incorrect code (e.g. in language server mode) Psalm should still use the same parser (and work around any issues that it produces).

## Docblock annotations are better than type-providing plugins

Psalm offers a plugin API that allows you to tell it what about your program's property types, return types and parameter types.

Psalm aims to operate in a space with other static analysis tools. The more users rely on plugins, the less chance those other tools have to understand the user's intent.

Psalm should encourage developers to use docblock annotations rather than type-providing plugins. This was a driving force in the adoption of [Conditional Types](../annotating_code/type_syntax/conditional_types.md) which allowed Psalm to replace some of its own internal type-providing plugins.

The other benefit to docblock annotations is verifiability – for the most part Psalm is able to verify that docblock annotations are correct, but it cannot provide many assurances when plugins are used.

This doesn’t mean that plugins as a whole are bad, or that they can’t provide useful types. A great adjacent use of plugins is to provide stubs with Psalm type annotations for libraries that don’t have them. This helps the PHP ecosystem because those stubs may eventually make their way into the project currently being stubbed.

## Docblock annotations that can be verified are better than those that cannot

Psalm currently supports a number of function/class docblock annotations that it's unable to verify:

- `@psalm-assert`, `@psalm-assert-if-true`, `@psalm-assert-if-false`
- `@property`, `@method`, `@mixin`

Whenever new docblock annotations are added, effort should be made to allow Psalm to verify their correctness.

## In certain circumstances docblock annotations are better than PHP 8 attributes

For information that's just designed to be consumed by static analysis tools, docblocks are a better home than PHP 8 attributes.

A rationale is provided in [this article](https://psalm.dev/articles/php-8-attributes).

---

### Contributing What Makes Psalm Complicated (`docs/contributing/what_makes_psalm_complicated.md`)

# Things that make developing Psalm complicated

This is a somewhat informal list that might aid others.

## Type inference

Type inference is one of the big things Psalm does. It tries to figure out what different PHP elements (function calls, if/for/foreach statements etc.) mean for the data in your code.

Within type inference there are a number of tricky areas:

#### Loops

Loops are hard to reason about - break and continue are a pain. This analysis mainly takes place in `LoopAnalyzer`

#### Combining types

There are lots of edge-cases when combining types together, given the many types Psalm supports. Type combining occurs in `TypeCombiner`.

#### Logical assertions

What effect do different PHP elements have on user-asserted logic in if conditionals, ternarys etc. This logic is spread between a number of different classes.

#### Generics & Templated code

Figuring out how templated code should work (`@template` tags) and how much it should work like it does in other languages (Hack, TypeScript etc.) is tricky. Psalm also supports things like nested templates (`@template T1 of T2`) which makes things trickier

## Detecting dead code

Detecting unused variables requires some fun [data-flow analysis](https://psalm.dev/articles/better-unused-variable-detection).

Detecting unused classes and methods between different runs requires maintaining references to those classes in cache (see below).

## Supporting the community
- **Supporting formal PHPDoc annotations**
- **Supporting informal PHPDoc annotations**
  e.g. `ArrayIterator|string[]` to denote an `ArrayIterator` over strings
- **non-Composer projects**
  e.g. WordPress

## Making Psalm fast

#### Parser-based reflection

Requires scanning everything necessary for analysis

#### Forking processes** (non-windows)

Mostly handled by code borrowed from Phan, but can introduce subtle issues, also requires to think about how to make work happen in processes

#### Caching thing

see below

## Cache invalidation

#### Invalidating analysis results

Requires tracking what methods/properties are used in what other files, and invalidating those results when linked methods change

#### Partial parsing

Reparsing bits of files that have changed, which is hard

## Language Server Support

#### Handling temporary file changes

When files change Psalm figures out what's changed within them to avoid re-analysing things unnecessarily

#### Dealing with malformed PHP code

When people write code, it's not always pretty as they write it. A language server needs to deal with that bad code somehow

## Fixing code with Psalter

#### Adding/replacing code

Figuring out what changed, making edits that could have been made by a human

#### Minimal diffs

hard to change more than you need

---

### Manipulating Code Fixing (`docs/manipulating_code/fixing.md`)

# Fixing Code

Psalm is good at finding potential issues in large codebases, but once found, it can be something of a gargantuan task to fix all the issues.

It comes with a tool, called Psalter, that helps you fix code.

You can either run it via its binary

```
vendor/bin/psalter [args]
```

or via Psalm's binary:

```
vendor/bin/psalm --alter [args]
```

## Safety features

Updating code is inherently risky, doing so automatically is even more so. I've added a few features to make it a little more reassuring:

- To see what changes Psalter will make ahead of time, you can run it with `--dry-run`.
- You can target particular versions of PHP via `--php-version`, so that (for example) you don't add nullable typehints to PHP 7.0 code, or any typehints at all to PHP 5.6 code. `--php-version` defaults to your current version.
- it has a `--safe-types` mode that will only update PHP 7 return typehints with information Psalm has gathered from non-docblock sources of type information (e.g. typehinted params, `instanceof` checks, other return typehints etc.)
- using `--allow-backwards-incompatible-changes=false` you can make sure to not create backwards incompatible changes


## Plugins

You can pass in your own manipulation plugins e.g.
```bash
vendor/bin/psalter --plugin=vendor/vimeo/psalm/examples/plugins/ClassUnqualifier.php --dry-run
```

The above example plugin converts all unnecessarily qualified classnames in your code to shorter aliased versions.

## Supported fixes

This initial release provides support for the following alterations, corresponding to the names of issues Psalm finds.
To fix all of these at once, run `vendor/bin/psalter --issues=all`

### MissingReturnType

Running `vendor/bin/psalter --issues=MissingReturnType --php-version=7.0` on

```php
<?php
function foo() {
  return "hello";
}
```

gives

```php
<?php
function foo() : string {
  return "hello";
}
```

and running `vendor/bin/psalter --issues=MissingReturnType --php-version=5.6` on

```php
<?php
function foo() {
  return "hello";
}
```

gives

```php
<?php
/**
 * @return string
 */
function foo() {
  return "hello";
}
```

### MissingClosureReturnType

As above, except for closures

### InvalidReturnType

Running `vendor/bin/psalter --issues=InvalidReturnType` on

```php
<?php
/**
 * @return int
 */
function foo() {
  return "hello";
}
```

gives

```php
<?php
/**
 * @return string
 */
function foo() {
  return "hello";
}
```

There's also support for return typehints, so running `vendor/bin/psalter --issues=InvalidReturnType` on

```php
<?php
function foo() : int {
  return "hello";
}
```

gives

```php
<?php
function foo() : string {
  return "hello";
}
```

### InvalidNullableReturnType

Running `vendor/bin/psalter --issues=InvalidNullableReturnType  --php-version=7.1` on

```php
<?php
function foo() : string {
  return rand(0, 1) ? "hello" : null;
}
```

gives

```php
<?php
function foo() : ?string {
  return rand(0, 1) ? "hello" : null;
}
```

and running `vendor/bin/psalter --issues=InvalidNullableReturnType  --php-version=7.0` on

```php
<?php
function foo() : string {
  return rand(0, 1) ? "hello" : null;
}
```

gives

```php
<?php
/**
 * @return string|null
 */
function foo() {
  return rand(0, 1) ? "hello" : null;
}
```

### InvalidFalsableReturnType

Running `vendor/bin/psalter --issues=InvalidFalsableReturnType` on

```php
<?php
function foo() : string {
  return rand(0, 1) ? "hello" : false;
}
```

gives

```php
<?php
/**
 * @return string|false
 */
function foo() {
  return rand(0, 1) ? "hello" : false;
}
```

### MissingParamType

Running `vendor/bin/psalter --issues=MissingParamType` on

```php
<?php
class C {
  public static function foo($s) : void {
    echo $s;
  }
}
C::foo("hello");
```

gives

```php
<?php
class C {
  /**
   * @param string $s
   */
  public static function foo($s) : void {
    echo $s;
  }
}
C::foo("hello");
```

### MissingPropertyType

Running `vendor/bin/psalter --issues=MissingPropertyType` on

```php
<?php
class A {
    public $foo;
    public $bar;
    public $baz;

    public function __construct()
    {
        if (rand(0, 1)) {
            $this->foo = 5;
        } else {
            $this->foo = "hello";
        }

        $this->bar = "baz";
    }

    public function setBaz() {
        $this->baz = [1, 2, 3];
    }
}
```

gives

```php
<?php
class A {
    /**
     * @var string|int
     */
    public $foo;

    public string $bar;

    /**
     * @var array<int, int>|null
     * @psalm-var non-empty-list<int>|null
     */
    public $baz;

    public function __construct()
    {
        if (rand(0, 1)) {
            $this->foo = 5;
        } else {
            $this->foo = "hello";
        }

        $this->bar = "baz";
    }

    public function setBaz() {
        $this->baz = [1, 2, 3];
    }
}
```

### MismatchingDocblockParamType

Given

```php
<?php
class A {}
class B extends A {}
class C extends A {}
class D {}
```

running `vendor/bin/psalter --issues=MismatchingDocblockParamType` on
```php
<?php
/**
 * @param B|C $first
 * @param D $second
 */
function foo(A $first, A $second) : void {}
```

gives

```php
<?php
/**
 * @param B|C $first
 * @param A $second
 */
function foo(A $first, A $second) : void {}
```

### MismatchingDocblockReturnType

Running `vendor/bin/psalter --issues=MismatchingDocblockReturnType` on
```php
<?php
/**
 * @return int
 */
function foo() : string {
  return "hello";
}
```

gives

```php
<?php
/**
 * @return string
 */
function foo() : string {
  return "hello";
}
```

### LessSpecificReturnType

Running `vendor/bin/psalter --issues=LessSpecificReturnType` on

```php
<?php
function foo() : ?string {
  return "hello";
}
```

gives

```php
<?php
function foo() : string {
  return "hello";
}
```

### PossiblyUndefinedVariable

Running `vendor/bin/psalter --issues=PossiblyUndefinedVariable` on

```php
<?php
function foo()
{
    if (rand(0, 1)) {
      $a = 5;
    }
    echo $a;
}
```

gives

```php
<?php
function foo()
{
    $a = null;
    if (rand(0, 1)) {
      $a = 5;
    }
    echo $a;
}
```


### PossiblyUndefinedGlobalVariable

Running `vendor/bin/psalter --issues=PossiblyUndefinedGlobalVariable` on

```php
<?php
if (rand(0, 1)) {
  $a = 5;
}
echo $a;
```

gives

```php
<?php
$a = null;
if (rand(0, 1)) {
  $a = 5;
}
echo $a;
```

### UnusedMethod

This removes private unused methods.

Running `vendor/bin/psalter --issues=UnusedMethod` on

```php
<?php
class A {
    private function foo() : void {}
}

new A();
```

gives

```php
<?php
class A {

}

new A();
```

### PossiblyUnusedMethod

This removes protected/public unused methods.

Running `vendor/bin/psalter --issues=PossiblyUnusedMethod` on

```php
<?php
class A {
    protected function foo() : void {}
    public function bar() : void {}
}

new A();
```

gives

```php
<?php
class A {

}

new A();
```

### UnusedProperty

This removes private unused properties.

Running `vendor/bin/psalter --issues=UnusedProperty` on

```php
<?php
class A {
    /** @var string */
    private $foo;
}

new A();
```

gives

```php
<?php
class A {

}

new A();
```

### PossiblyUnusedProperty

This removes protected/public unused properties.

Running `vendor/bin/psalter --issues=PossiblyUnusedProperty` on

```php
<?php
class A {
    /** @var string */
    public $foo;

    /** @var string */
    protected $bar;
}

new A();
```

gives

```php
<?php
class A {

}

new A();
```

### UnusedVariable

This removes unused variables.

Running `vendor/bin/psalter --issues=UnusedVariable` on

```php
<?php
function foo(string $s) : void {
    $a = 5;
    $b = 6;
    $c = $b += $a -= intval($s);
    echo "foo";
}
```

gives

```php
<?php
function foo(string $s) : void {
    echo "foo";
}
```

### UnnecessaryVarAnnotation

This removes unused `@var` annotations

Running `vendor/bin/psalter --issues=UnnecessaryVarAnnotation` on

```php
<?php
function foo() : string {
    return "hello";
}

/** @var string */
$a = foo();
```

gives

```php
<?php
function foo() : string {
    return "hello";
}

$a = foo();
```

### ParamNameMismatch

This aligns child class param names with their parent.

Running `vendor/bin/psalter --issues=ParamNameMismatch` on

```php
<?php

class A {
    public function foo(string $str, bool $b = false) : void {}
}

class AChild extends A {
    public function foo(string $string, bool $b = false) : void {
        echo $string;
    }
}
```

gives

```php
<?php

class A {
    public function foo(string $str, bool $b = false) : void {}
}

class AChild extends A {
    public function foo(string $str, bool $b = false) : void {
        echo $str;
    }
}
```

---

### Manipulating Code Refactoring (`docs/manipulating_code/refactoring.md`)

# Refactoring Code

Sometimes you want to make big changes to your codebase like moving methods or classes.

Psalm has a refactoring tool you can access with either `vendor/bin/psalm-refactor` or `vendor/bin/psalm --refactor`, followed by appropriate commands.

## Moving all classes from one namespace to another

```
vendor/bin/psalm-refactor --move "Ns1\*" --into "Some\Other\Namespace"
```

This moves all classes in `Ns1` (e.g. `Ns1\Foo`, `Ns1\Baz`) into the specified namespace. Files are moved as necessary.

## Moving classes between namespaces

```
vendor/bin/psalm-refactor --move "Ns1\Foo" --into "Ns2"
```

This tells Psalm to move class `Ns1\Foo` into the namespace `Ns2`, so any reference to `Ns1\Foo` becomes `Ns2\Foo`). Files are moved as necessary.

## Moving and renaming classes

```
vendor/bin/psalm-refactor --rename "Ns1\Foo" --to "Ns2\Bar\Baz"
```

This tells Psalm to move class `Ns1\Foo` into the namespace `Ns2\Bar` and rename it to `Baz`, so any reference to `Ns1\Foo` becomes `Ns2\Bar\Baz`). Files are moved as necessary.

## Moving methods between classes

```
vendor/bin/psalm-refactor --move "Ns1\Foo::bar" --into "Ns2\Baz"
```

This tells Psalm to move a method named `bar` inside `Ns1\Foo` into the class `Ns2\Baz`, so any reference to `Ns1\Foo::bar` becomes `Ns2\Baz::bar`). Psalm currently allows you to move static methods between arbitrary classes, and instance methods into child classes of that instance.

## Moving and renaming methods

```
vendor/bin/psalm-refactor --rename "Ns1\Foo::bar" --to "Ns2\Baz::bat"
```

This tells Psalm to move method `Ns1\Foo::bar` into the class `Ns2\Baz` and rename it to `bat`, so any reference to `Ns1\Foo::bar` becomes `Ns2\Baz::bat`).

---

### Running Psalm Checking Non Php Files (`docs/running_psalm/checking_non_php_files.md`)

# Checking non-PHP files

Psalm supports the ability to check various PHPish files by extending the `FileChecker` class. For example, if you have a template where the variables are set elsewhere, Psalm can scrape those variables and check the template with those variables pre-populated.

An example TemplateChecker is provided [here](https://github.com/vimeo/psalm/blob/master/examples/TemplateChecker.php).

## Using `psalm.xml`

To ensure your custom `FileChecker` is used, you must update the Psalm `fileExtensions` config in psalm.xml:
```xml
<fileExtensions>
    <extension name=".php" />
    <extension name=".phpt" checker="path/to/TemplateChecker.php" />
</fileExtensions>
```

## Using custom plugin

Plugins can register their own custom scanner  and analyzer implementations for particular file extensions.

```php
<?php
namespace Psalm\Example;

use Psalm\Plugin\PluginEntryPointInterface;
use Psalm\Plugin\PluginFileExtensionsInterface;
use Psalm\Plugin\FileExtensionsInterface;
use Psalm\Plugin\RegistrationInterface;

class CustomPlugin implements PluginEntryPointInterface, PluginFileExtensionsInterface
{
    public function __invoke(RegistrationInterface $registration, ?\SimpleXMLElement $config = null): void
    {
        // ... regular plugin processes, stub registration, hook registration
    }

    public function processFileExtensions(FileExtensionsInterface $fileExtensions, ?SimpleXMLElement $config = null): void
    {
        $fileExtensions->addFileTypeScanner('phpt', TemplateScanner::class);
        $fileExtensions->addFileTypeAnalyzer('phpt', TemplateAnalyzer::class);
    }    
}
```

---

### Running Psalm Command Line Usage (`docs/running_psalm/command_line_usage.md`)

# Running Psalm

Once you've set up your config file, you can run Psalm from your project's root directory with
```bash
./vendor/bin/psalm
```

and Psalm will scan all files in the project referenced by `<projectFiles>`.

If you want to run on specific files, use
```bash
./vendor/bin/psalm file1.php [file2.php...]
```

## Command-line options

Run with `--help` to see a list of options that Psalm supports.

## Exit status

Psalm exits with status `0` when it successfully completed and found no issues,
`1` when there was a problem running Psalm and `2` when it completed
successfully but found some issues. Any exit status apart from those indicate
some internal problem.

## Shepherd

Psalm currently offers some GitHub integration with public projects.

Add `--shepherd` to send information about your build to https://shepherd.dev.

Currently, Shepherd tracks type coverage (the percentage of types Psalm can infer) on `master` branches.

## Running Psalm faster

To run Psalm up to 50% faster, use the [official docker image](https://psalm.dev/docs/running_psalm/installation/#docker-image).  

Psalm also has a couple of command-line options that will result in faster builds:

- `--threads=[n]` to run Psalm’s analysis in a number of threads
- `--diff` which only checks files you’ve updated since the last run (and their dependents).

In Psalm 4 `--diff` is turned on by default (you can disable it with `--no-diff`).

Data from the last run is stored in the *cache directory*, which may be set in [configuration](./configuration.md).
If you are running Psalm on a build server, you may want to configure the server to ensure that the cache directory
is preserved between runs.

Running them together (e.g. `--threads=8 --diff`) will result in the fastest possible Psalm run.

## Reviewing issues in your IDE of choice

Psalm now offers a `psalm-review` tool which allows you to manually review issues one by one in your favorite IDE.  

```bash
./vendor/bin/psalm-review report.json [code|phpstorm|code-server] [ inv|rev|[~-]IssueType1 ] [ [~-]IssueType2 ] ...
```

The tool may also be run using the main `psalm` entry point, useful for example when working with the phar:

```bash
./vendor/bin/psalm.phar --review report.json [code|phpstorm|code-server] [ inv|rev|[~-]IssueType1 ] [ [~-]IssueType2 ] ...
```

`psalm-review` parses the Psalm JSON report in report.json (generated using `vendor/bin/psalm --report=report.json`) and opens the specified IDE at the line and column of the issue, one by one for all issues; press enter to go to the next issue, `q` to quit.

The IDE argument is optional when running inside a supported IDE's integrated terminal — PhpStorm, VS Code, and code-server are auto-detected via environment variables. When running from an external terminal, the IDE must be specified explicitly.

The extra arguments may be used to filter only for issues of the specified types, or for all issues except the specified types (with the `~` or `-` inversion).  

The `rev` or `inv` keywords may be used to start from the end of the report instead of at the beginning.

---

### Running Psalm Configuration (`docs/running_psalm/configuration.md`)

# Configuration

Psalm uses an XML config file (by default, `psalm.xml`). A barebones example looks like this:

```xml
<?xml version="1.0"?>
<psalm>
    <projectFiles>
        <directory name="src" />
    </projectFiles>
</psalm>
```

Configuration file may be split into several files using [XInclude](https://www.w3.org/TR/xinclude/) tags (c.f. previous example):
#### psalm.xml
```xml
<?xml version="1.0"?>
<psalm
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="https://getpsalm.org/schema/config"
    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
    xmlns:xi="http://www.w3.org/2001/XInclude"
>
    <xi:include href="files.xml"/>
</psalm>
```
#### files.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<projectFiles xmlns="https://getpsalm.org/schema/config">
    <file name="Bar.php" />
    <file name="Bat.php" />
</projectFiles>
```

## Different configuration file

You can also create a different configuration file, then run Psalm with:
```bash
vendor/bin/psalm --config=other-psalm-config.xml
```

## Optional &lt;psalm /&gt; attributes

### Coding style

#### errorLevel

```xml
<psalm
  errorLevel="[int]"
/>
```
This corresponds to Psalm‘s [error-detection level](error_levels.md).

#### reportMixedIssues

```xml
<psalm
  reportMixedIssues="[bool]"
/>
```
Setting this to `"false"` hides all issues with `Mixed` types in Psalm’s output. If not given, this defaults to `"false"` when `errorLevel` is 3 or higher, and `"true"` when the error level is 1 or 2.

#### totallyTyped

\(Deprecated\) This setting has been replaced by `reportMixedIssues` which is automatically enabled when `errorLevel` is 1.

#### resolveFromConfigFile

```xml
<psalm
  resolveFromConfigFile="[bool]"
/>
```
If this is enabled, relative directories mentioned in the config file will be resolved relative to the location
of the config file. If it is disabled, or absent they will be resolved relative to the working directory of the Psalm process.

New versions of Psalm enable this option when generating config files. Older versions did not include it.

#### useDocblockTypes

```xml
<psalm
  useDocblockTypes="[bool]"
>
```
Whether or not to use types as defined in docblocks. Defaults to `true`.

#### useDocblockPropertyTypes

```xml
<psalm
  useDocblockPropertyTypes="[bool]"
>
```
If not using all docblock types, you can still use docblock property types. Defaults to `false` (though only relevant if `useDocblockTypes` is `false`).

#### docblockPropertyTypesSealProperties

```xml
<psalm
  docblockPropertyTypesSealProperties="[bool]"
>
```
Whether using @property in class docblocks should imply @psalm-seal-properties. Defaults to `true`.

#### usePhpDocMethodsWithoutMagicCall

```xml
<psalm
  usePhpDocMethodsWithoutMagicCall="[bool]"
>
```
The PHPDoc `@method` annotation normally only applies to classes with a `__call` method. Setting this to `true` allows you to use the `@method` annotation to override inherited method return types. Defaults to `false`.

#### usePhpDocPropertiesWithoutMagicCall

```xml
<psalm
  usePhpDocPropertiesWithoutMagicCall="[bool]"
>
```
The PHPDoc `@property`, `@property-read` and `@property-write` annotations normally only apply to classes with `__get`/`__set` methods. Setting this to `true` allows you to use the `@property`, `@property-read` and `@property-write` annotations to override property existence checks and resulting property types. Defaults to `false`.

#### disableVarParsing

```xml
<psalm
  disableVarParsing="[bool]"
/>
```

Disables parsing of `@var` PHPDocs everywhere except for properties. Setting this to `true` can remove many false positives due to outdated `@var` annotations, used before integrations of Psalm generics and proper typing, enforcing Single Source Of Truth principles. Defaults to `false`.

#### strictBinaryOperands

```xml
<psalm
  strictBinaryOperands="[bool]"
>
```
If true we force strict typing on numerical and string operations (see https://github.com/vimeo/psalm/issues/24). Defaults to `true`.

#### allowBoolToLiteralBoolComparison

```xml
<psalm
  allowBoolToLiteralBoolComparison="[bool]"
>
```

If false, disallows comparing a boolean to a literal boolean (mostly a codestyle rule, not a bug detection rule; see [RedundantIdentityWithTrue](https://psalm.dev/docs/running_psalm/issues/RedundantIdentityWithTrue/)). Defaults to `true`.

#### rememberPropertyAssignmentsAfterCall

```xml
<psalm
  rememberPropertyAssignmentsAfterCall="[bool]"
>
```
Setting this to `false` means that function calls will cause Psalm to forget what it knew about object properties within the scope of the function it's currently analysing, unless the callee can't write them (see [property refinements after calls](../annotating_code/purity_model.md#property-refinements-after-calls)). This duplicates functionality that Hack has. Defaults to `true`.

#### allowStringToStandInForClass

```xml
<psalm
  allowStringToStandInForClass="[bool]"
>
```
When `true`, strings can be used as classes, meaning `$some_string::someMethod()` is allowed. If `false`, only class constant strings (of the form `Foo\Bar::class`) can stand in for classes, otherwise an `InvalidStringClass` issue is emitted. Defaults to `false`.

#### disableSuppressAll

```xml
<psalm
  disableSuppressAll="[bool]"
>
```
When `true`, disables wildcard suppression of all issues with `@psalm-suppress all`. Defaults to `true`.

#### memoizeMethodCallResults

```xml
<psalm
  memoizeMethodCallResults="[bool]"
>
```
When `true`, the results of method calls without arguments passed are remembered between repeated calls of that method on a given object. Defaults to `false`.

#### hoistConstants

```xml
<psalm
  hoistConstants="[bool]"
>
```
When `true`, constants defined in a function in a file are assumed to be available when requiring that file, and not just when calling that function. Defaults to `false` (i.e. constants defined in functions will *only* be available for use when that function is called)

#### addParamDefaultToDocblockType

```xml
<psalm
  addParamDefaultToDocblockType="[bool]"
>
```
Occasionally a param default will not match up with the docblock type. By default, Psalm emits an issue. Setting this flag to `true` causes it to expand the param type to include the param default. Defaults to `false`.

#### checkForThrowsDocblock
```xml
<psalm
  checkForThrowsDocblock="[bool]"
>
```
When `true`, Psalm will check that the developer has supplied `@throws` docblocks for every exception thrown in a given function or method. Defaults to `false`.

#### checkForThrowsInGlobalScope
```xml
<psalm
  checkForThrowsInGlobalScope="[bool]"
>
```
When `true`, Psalm will check that the developer has caught every exception in global scope. Defaults to `false`.

#### ignoreInternalFunctionFalseReturn

```xml
<psalm
  ignoreInternalFunctionFalseReturn="[bool]"
>
```
When `true`, Psalm ignores possibly-false issues stemming from return values of internal functions (like `preg_split`) that may return false, but do so rarely. Defaults to `false`.

#### ignoreInternalFunctionNullReturn

```xml
<psalm
  ignoreInternalFunctionNullReturn="[bool]"
>
```
When `true`, Psalm ignores possibly-null issues stemming from return values of internal array functions (like `current`) that may return null, but do so rarely. Defaults to `false`.

#### inferPropertyTypesFromConstructor

```xml
<psalm
  inferPropertyTypesFromConstructor="[bool]"
>
```
When `true`, Psalm infers property types from assignments seen in straightforward constructors. Defaults to `true`.

#### findUnusedVariablesAndParams
```xml
<psalm
  findUnusedVariablesAndParams="[bool]"
>
```
When `true`, Psalm will attempt to find all unused variables, the equivalent of running with `--find-unused-variables`. Defaults to `false`.

#### findUnusedCode
```xml
<psalm
  findUnusedCode="[bool]"
>
```
When `true`, Psalm will attempt to find all unused code (including unused variables), the equivalent of running with `--find-unused-code`. Defaults to `true`.

Unused-code detection is based on a graph of references between code elements, resolved by reachability from the program's entry points (the public API, top-level code, free functions, and code outside of the project directories). As a result, a class, method, property or constant that is referenced only by other unused code — including cycles of otherwise unreferenced code — is reported as unused. Suppressing an unused-code issue (e.g. `@psalm-suppress UnusedClass`) only silences the report for that symbol; it does not turn the symbol into an entry point, so code that only it references is still reported.

This is enabled by default since Psalm 6, so unused code issues are reported even without passing `--find-unused-code` (or `--find-dead-code`). Set `findUnusedCode="false"` to turn it off.

#### forceJit
```xml
<psalm
  forceJit="[bool]"
>
```
When `true`, Psalm will enable JIT acceleration and exit immediately if it cannot be enabled, the equivalent of running with `--force-jit`. When `false` (default), Psalm runs without JIT.

#### noCache
```xml
<psalm
  noCache="[bool]"
>
```
When `true`, Psalm will disable usage of the cache, the equivalent of running with `--no-cache`. Defaults to `false`.

#### arrayCache
```xml
<psalm
  arrayCache="[bool]"
>
```
When `false`, Psalm will disable usage of the array cache. 

The array cache is used together with the file cache to avoid re-loading cache entries when re-scanning the same file, which offers a nice performance improvement.

Defaults to `true`.

#### disallowLiteralKeysOnUnshapedArrays
```xml
<psalm
  disallowLiteralKeysOnUnshapedArrays="[bool]"
>
```
When `true`, Psalm will emit issues when using literal keys on unshaped arrays (useful to enforce usage of shaped arrays). Defaults to `false`.

#### allFunctionsGlobal
```xml
<psalm
  allFunctionsGlobal="[bool]"
>
```
When `true`, Psalm will treat all functions declared in scanned files as available to all files, even if they aren't loaded by the Composer autoloader (useful for legacy codebases which make heavy use of `require`/`include`, instead of Composer's autoloader). Defaults to `false`.

#### allConstantsGlobal
```xml
<psalm
  allConstantsGlobal="[bool]"
>
```

When `true`, Psalm will treat all constants declared in scanned files as available to all files, even if they aren't loaded by the Composer autoloader (useful for legacy codebases which make heavy use of `require`/`include`, instead of Composer's autoloader). Defaults to `false`.

#### findUnusedPsalmSuppress
```xml
<psalm
  findUnusedPsalmSuppress="[bool]"
>
```
When `true`, Psalm will report all `@psalm-suppress` annotations that aren't used, the equivalent of running with `--find-unused-psalm-suppress`. Defaults to `false`.

#### ensureArrayStringOffsetsExist
```xml
<psalm
  ensureArrayStringOffsetsExist="[bool]"
>
```
When `true`, Psalm will complain when referencing an explicit string offset on an array e.g. `$arr['foo']` without a user first asserting that it exists (either via an `isset` check or via an object-like array). Defaults to `false`.

#### ensureArrayIntOffsetsExist
```xml
<psalm
  ensureArrayIntOffsetsExist="[bool]"
>
```
When `true`, Psalm will complain when referencing an explicit integer offset on an array e.g. `$arr[7]` without a user first asserting that it exists (either via an `isset` check or via an object-like array). Defaults to `false`.

#### ensureOverrideAttribute
```xml
<psalm
  ensureOverrideAttribute="[bool]"
>
```
When `true`, Psalm will report class and interface methods that override a method on a parent, but do not have an `Override` attribute. Defaults to `true`.

#### phpVersion
```xml
<psalm
  phpVersion="[string]"
>
```
Set the php version Psalm should assume when checking and/or fixing the project. If this attribute is not set, Psalm uses the declaration in `composer.json` if one is present. It will check against the earliest version of PHP that satisfies the declared `php` dependency

This can be overridden on the command-line using the `--php-version=` flag which takes the highest precedence over both the `phpVersion` setting and the version derived from `composer.json`.

#### skipChecksOnUnresolvableIncludes
```xml
<psalm
  skipChecksOnUnresolvableIncludes="[bool]"
>
```

When `true`, Psalm will skip checking classes, variables and functions after it comes across an `include` or `require` it cannot resolve. This allows code to reference functions and classes unknown to Psalm.

This defaults to `false`.

#### sealAllMethods

```xml
<psalm
  sealAllMethods="[bool]"
>
```

When `true`, Psalm will treat all classes as if they had sealed methods, meaning that if you implement the magic method `__call`, you also have to add `@method` for each magic method. Defaults to true.

#### sealAllProperties

```xml
<psalm
  sealAllProperties="[bool]"
>
```

When `true`, Psalm will treat all classes as if they had sealed properties, meaning that Psalm will disallow getting and setting any properties not contained in a list of `@property` (or `@property-read`/`@property-write`) annotations and not explicitly defined as a `property`. Defaults to true.

#### runTaintAnalysis

```xml
<psalm
  runTaintAnalysis="[bool]"
>
```

When `true` (the default), Psalm will run [Taint Analysis](../security_analysis/index.md) on your codebase. This config is the same as if you were running Psalm with `--taint-analysis`.

#### reportInfo

```xml
<psalm
  reportInfo="[bool]"
>
```

When `false`, Psalm will not consider issue at lower level than `errorLevel` as `info` (they will be suppressed instead). This can be a big improvement in analysis time for big projects. However, this config will prevent Psalm to count or suggest fixes for suppressed issue

#### allowNamedArgumentCalls

```xml
<psalm
  allowNamedArgumentCalls="[bool]"
>
```

When `false`, Psalm will not report `ParamNameMismatch` issues in your code anymore. This does not replace the use of individual `@no-named-arguments` to prevent external access to a library's method or to reduce the type to a `list` when using variadics

#### triggerErrorExits

```xml
<psalm
   triggerErrorExits="[string]"
>
```

Describe the behavior of trigger_error. `always` means it always exits, `never` means it never exits, `default` means it exits only for `E_USER_ERROR`. Default is `default`

### Running Psalm

#### autoloader
```xml
<psalm
  autoloader="[string]"
>
```
If your application registers one or more custom autoloaders, and/or declares universal constants/functions, this autoloader script will be executed by Psalm before scanning starts. Psalm always registers composer's autoloader by default.

#### throwExceptionOnError
```xml
<psalm
  throwExceptionOnError="[bool]"
>
```
Useful in testing, this makes Psalm throw a regular-old exception when it encounters an error. Defaults to `false`.

#### hideExternalErrors
```xml
<psalm
  hideExternalErrors="[bool]"
>
```
Whether or not to show issues in files that are used by your project files, but which are not included in `<projectFiles>`. Defaults to `false`.

#### hideAllErrorsExceptPassedFiles
```xml
<psalm
  hideAllErrorsExceptPassedFiles="[bool]"
>
```
Whether or not to report issues only for files that were passed explicitly as arguments in CLI. This means any files that are loaded with require/include will not report either, if not set in CLI. Useful if you want to only check errors in a single or selected files. Defaults to `false`.

#### cacheDirectory
```xml
<psalm
  cacheDirectory="[string]"
>
```
The directory used to store Psalm's cache data - if you specify one (and it does not already exist), its parent directory must already exist, otherwise Psalm will throw an error.

Defaults to `$XDG_CACHE_HOME/psalm`. If `$XDG_CACHE_HOME` is either not set or empty, a default equal to `$HOME/.cache/psalm` is used or `sys_get_temp_dir() . '/psalm'` when not defined.

#### allowFileIncludes
```xml
<psalm
  allowFileIncludes="[bool]"
>
```
Whether or not to allow `require`/`include` calls in your PHP. Defaults to `true`.

#### ignoreIncludeSideEffects
```xml
<psalm
  ignoreIncludeSideEffects="[bool]"
>
```
Whether or not to ignore side effects of includes.  

Ignoring include side effects can significantly speed up scans on legacy codebases, but changes to variables or variables defined inside of included files will not be visible to Psalm (functions, constants and classes will still be visible anyway, especially if the hoistConstants, allConstantsGlobal, allFunctionsGlobal configuration parameters are set to true).  

Defaults to `false`.

#### respectIncludeOnce
```xml
<psalm
  respectIncludeOnce="[bool]"
>
```
Whether or not to process files after the first `require_once()` or `include_once()` call.  

By default, Psalm treats `require_once()` and `include_once()` calls as if they were `require()` or `include()` calls in an attempt to consider all possible permutations of file include order.  Respecting `require_once()` and `include_once()` behavior can significantly speed up scans on codebases with circular `require_once()` or `include_once()` calls.  While potentially less comprehensive, this setting aims to more closely mimic PHP's runtime behavior.

Defaults to `false`.

#### serializer
```xml
<psalm
  serializer="['igbinary'|'default']"
>
```
Allows you to hard-code a serializer for Psalm to use when caching data. By default, Psalm uses `ext-igbinary` *if* the version is greater than or equal to 2.0.5, otherwise it defaults to PHP's built-in serializer.

#### compressor
```xml
<psalm
  compressor="['lz4'|'deflate'|'off']"
>
```
Allows you to hard-code a compressor for Psalm's cache. By default, Psalm uses `ext-zlib` deflate, if it's enabled.

#### threads
```xml
<psalm
        threads="[int]"
>
```
Allows you to hard-code the number of threads Psalm will use (similar to `--threads` on the command line). This value will be used in place of detecting threads from the host machine, but will be overridden by using `--threads` or `--debug` (which sets threads to 1) on the command line

#### scanThreads
```xml
<psalm
        scanThreads="[int]"
>
```
Allows you to hard-code the number of threads Psalm will use during the scan phase (as opposed to the analysis phase, controlled by the `threads` field) (similar to `--scan-threads` on the command line). This value will be used in place of detecting threads from the host machine, but will be overridden by using `--scan-threads`, `--threads` or `--debug` (which sets threads to 1) on the command line.

#### maxStringLength
```xml
<psalm
  maxStringLength="1000"
>
```
This setting controls the maximum length of literal strings that will be transformed into a literal string type during Psalm analysis.
Strings longer than this value (by default 1000 bytes) will be transformed in a generic `non-empty-string` type, instead.

Please note that changing this setting might introduce unwanted side effects and those side effects won't be considered as bugs.

#### maxShapedArraySize
```xml
<psalm
  maxShapedArraySize="100"
>
```
This setting controls the maximum size of shaped arrays that will be transformed into a shaped `array{key1: "value", key2: T}` type during Psalm analysis.
Arrays bigger than this value (100 by default) will be transformed in a generic `non-empty-array` type, instead.

Please note that changing this setting might introduce unwanted side effects and those side effects won't be considered as bugs.

#### longScanWarning
```xml
<psalm
  longScanWarning="10.0"
>
```

Specifies the maximum scan and analysis duration for individual files; files which take longer than the specified amount of seconds (as a floating point, so values smaller than one second are also accepted) will print out a warning to CLI (the scan will **not** be interrupted).  

Only used in multithreaded mode, defaults to 10 seconds.  

#### restrictReturnTypes

```xml
<psalm
  restrictReturnTypes="true"
>
```

Emits `LessSpecificReturnType` when the declared return type is not as tight as
the inferred return type.

This code:
```php
function getOne(): int // declared type: int
{
    return 1; // inferred type: 1 (int literal)
}
```
Will give this error: `LessSpecificReturnType - The inferred return type '1' for
getOne is more specific than the declared return type 'int'`

To fix the error, you should specify the more specific type in the doc-block:
```php
/**
 * @return 1
 */
function getOne(): int
{
    return 1;
}
```

**Warning**: Forcing a tighter type is not always the best course of action and
may cause unexpected results. The following code is invalid with
`restrictReturnTypes="true"`:
```php
class StandardCar {
    /**
     * @return list{'motor', 'brakes', 'wheels'}
     */
    public function getSystems(): array {
        return ['motor', 'brakes', 'wheels'];
    }
}

class PremiumCar extends StandardCar {
    /**
     * @return list{'motor', 'brakes', 'wheels', 'rear parking sensor'}
     */
    public function getSystems(): array {
        return ['motor', 'brakes', 'wheels', 'rear parking sensor'];
    }
}
```
`ImplementedReturnTypeMismatch - The inherited return type 'list{'motor', 'brakes', 'wheels'}' for StandardCar::getSystems is different to the implemented return type for PremiumCar::getsystems 'list{'motor', 'brakes', 'wheels', 'rear parking sensor'}'`

#### findUnusedBaselineEntry

Emits [UnusedBaselineEntry](issues/UnusedBaselineEntry.md) when a baseline entry
is not being used to suppress an issue. Defaults to `true`.

#### findUnusedIssueHandlerSuppression

Emits [UnusedIssueHandlerSuppression](issues/UnusedIssueHandlerSuppression.md) when a suppressed issue handler
is not being used to suppress an issue. Defaults to `true`.

## Project settings

#### &lt;projectFiles&gt;
Contains a list of all the directories that Psalm should inspect. You can also specify a set of files and folders to ignore with the `<ignoreFiles>` directive.  By default, ignored files/folders are required to exist.  An `allowMissingFiles` attribute can be added for ignored files/folders than may or may not exist.
```xml
<projectFiles>
  <directory name="src" />
  <ignoreFiles>
    <directory name="src/Stubs" />
  </ignoreFiles>
  <ignoreFiles allowMissingFiles="true">
    <directory name="path-that-may-not-exist" />
  </ignoreFiles>
</projectFiles>
```

#### &lt;extraFiles&gt;
Optional. Same format as `<projectFiles>`. Directories Psalm should load but not inspect.

#### &lt;fileExtensions&gt;
Optional. A list of extensions to search over. See [Checking non-PHP files](checking_non_php_files.md) to understand how to extend this.

#### &lt;enableExtensions&gt;
Optional. A list of extensions to enable. By default, only extensions required by your composer.json will be enabled.
```xml
<enableExtensions>
  <extension name="decimal"/>
  <extension name="pdo"/>
</enableExtensions>
```

#### &lt;disableExtensions&gt;
Optional. A list of extensions to disable. By default, only extensions required by your composer.json will be enabled.
```xml
<disableExtensions>
  <extension name="gmp"/>
</disableExtensions>
```

#### &lt;plugins&gt;
Optional. A list of `<plugin filename="path_to_plugin.php" />` entries. See the [Plugins](plugins/using_plugins.md) section for more information.

#### &lt;issueHandlers&gt;
Optional. If you don't want Psalm to complain about every single issue it finds, the issueHandler tag allows you to configure that. [Dealing with code issues](dealing_with_code_issues.md) tells you more.

#### &lt;unsuppressibleIssues&gt;
Optional. A list of issues that can't be suppressed: Psalm reports them as errors whatever `@psalm-suppress`, `<issueHandlers>`, the [error level](error_levels.md), `reportMixedIssues` and the baseline say.

```xml
<unsuppressibleIssues>
  
  <issue name="TaintedInput" />
  <issue name="PossiblyNullReference" />
  
  <issue name="Vendor\Plugin\Issue\SomeIssue" />
</unsuppressibleIssues>
```

An entry names an issue, or a class or interface several issues extend, which makes all of them unsuppressible: `TaintedInput` for every taint issue, `MixedIssue` for every `Mixed*` issue, `ClassIssue`, `MethodIssue`, `PropertyIssue`, `ArgumentIssue`, `FunctionIssue`, `ClassConstantIssue`, `VariableIssue`, `PluginIssue` for every issue of a plugin, or `CodeIssue` for every issue. An issue of a plugin is named by the fully qualified name of its class.

Taint issues can only be suppressed in docblocks all at once, with `@psalm-suppress TaintedInput`, which stops tracking taints in the function or the statement it annotates: if any taint issue is unsuppressible, it doesn't, and every taint issue found there is reported.

The issues are still only reported in the files of `<projectFiles>` that aren't ignored. A `@psalm-suppress` of an unsuppressible issue is never used, so [findUnusedPsalmSuppress](#findunusedpsalmsuppress) reports it, and a baseline entry for one is never used either: `--set-baseline` and `--update-baseline` leave them out, and [findUnusedBaselineEntry](#findunusedbaselineentry) reports those of an existing baseline.

#### &lt;mockClasses&gt;
Optional. Do you use mock classes in your tests? If you want Psalm to ignore them when checking files, include a fully-qualified path to the class with `<class name="Your\Namespace\ClassName" />`

#### &lt;universalObjectCrates&gt;
Optional. Do you have objects with properties that cannot be determined statically? If you want Psalm to treat all properties on a given classlike as mixed, include a fully-qualified path to the class with `<class name="Your\Namespace\ClassName" />`. By default, `stdClass` and `SimpleXMLElement` are configured to be universal object crates.

#### &lt;stubs&gt;
Optional. If your codebase uses classes and functions that are not visible to Psalm via reflection
(e.g. if there are internal packages that your codebase relies on that are not available on the machine running Psalm),
you can use stub files. Used by PhpStorm (a popular IDE) and others, stubs provide a description of classes and
functions without the implementations.

You can find a list of stubs for common classes [here](https://github.com/JetBrains/phpstorm-stubs).
List out each file with `<file name="path/to/file.php" />`. In case classes to be tested use parent classes
or interfaces defined in a stub file, this stub should be configured with attribute `preloadClasses="true"`.

```xml
<stubs>
  <file name="path/to/file.php" />
  <file name="path/to/abstract-class.php" preloadClasses="true" />
</stubs>
```

Stubs aren't analyzed, but the issues of their docblocks (e.g. `InvalidDocblock`) are reported, also for the stubs
plugins add, so that an annotation a stub gets wrong isn't silently dropped.

Note: some extension stubs are already built into Psalm, and can be enabled by requiring the extension in your `composer.json` or by using the [enableExtensions](https://psalm.dev/docs/running_psalm/configuration/#enableextensions) config key.  

#### &lt;ignoreExceptions&gt;
Optional. A list of exceptions to not report for `checkForThrowsDocblock` or `checkForThrowsInGlobalScope`. The `class` tag will make Psalm ignore only instances of the specified class, while `classAndDescendants` will make Psalm also ignore subclasses. If an exception has `onlyGlobalScope` set to `true`, only `checkForThrowsInGlobalScope` is ignored for that exception, e.g.
```xml
<ignoreExceptions>
  <class name="fully\qualified\path\Exc" onlyGlobalScope="true" />
  <classAndDescendants name="fully\qualified\path\OtherExc" />
</ignoreExceptions>
```

#### &lt;globals&gt;
Optional. If your codebase uses global variables that are accessed with the `global` keyword, you can declare their type.  e.g.
```xml
<globals>
  <var name="globalVariableName" type="type" />
</globals>
```

Some frameworks and libraries expose functionalities through e.g. `$GLOBALS[DB]->query($query)`.
The  following configuration declares custom types for super-globals (`$GLOBALS`, `$_GET`, ...).

```xml
<globals>
  <var name="GLOBALS" type="array{DB: MyVendor\DatabaseConnection, VIEW: MyVendor\TemplateView}" />
  <var name="_GET" type="array{data: array<string, string>}" />
</globals>
```

The example above declares global variables as shown below

- `$GLOBALS`
    - `DB` of type `MyVendor\DatabaseConnection`
    - `VIEW` of type `MyVendor\TemplateView`
- `$_GET`
    - `data` e.g. like `["id" => "123", "title" => "Nice"]`

#### &lt;forbiddenFunctions&gt;
Optional. Allows you to specify a list of functions that should emit the [`ForbiddenCode`](issues/ForbiddenCode.md) issue type.

```xml
<forbiddenFunctions>
  <function name="var_dump" />
  <function name="dd" />
</forbiddenFunctions>
```

#### &lt;forbiddenConstants&gt;
Optional. Allows you to specify a list of constants that should emit the [`ForbiddenCode`](issues/ForbiddenCode.md) issue type.

```xml
<forbiddenConstants>
  <constant name="FILTER_VALIDATE_URL" />
</forbiddenConstants>
```

#### &lt;taintAnalysis&gt;
Optional. Settings of the [security analysis](../security_analysis/index.md):
- `<ignoreFiles>`: the files and directories whose taint paths are not reported (see
  [Avoiding files in taint paths](../security_analysis/avoiding_false_positives.md#avoiding-files-in-taint-paths)).
- `<taints>`: custom taints, which the annotations can then name without a plugin registering them. Each can be added
  to aliases of built-in taints (`input`, `tainted`, `input_except_sleep`) with `<alias>`: a taint added to `input` is
  user input, which the built-in sources give (see
  [Custom taints declared in the configuration](../security_analysis/custom_taint_sources.md#custom-taints-declared-in-the-configuration)).

```xml
<taintAnalysis>
  <taints>
    <taint name="file_upload">
      <alias name="input" />
    </taint>
    <taint name="session_id" />
  </taints>
</taintAnalysis>
```

## Accessing Psalm configuration in plugins

Plugins can access or modify the global configuration in plugins using
[singleton Psalm\Config](https://github.com/vimeo/psalm/blob/master/src/Psalm/Config.php).

```php
$config = \Psalm\Config::getInstance();
if (!isset($config->globals['$GLOBALS'])) {
    $config->globals['$GLOBALS'] = 'array{data: array<string, string>}';
}
```

---

### Running Psalm Dealing With Code Issues (`docs/running_psalm/dealing_with_code_issues.md`)

# Dealing with code issues

Psalm has a large number of [code issues](issues.md). Each project can specify its own reporting level for a given issue.

Code issue levels in Psalm fall into three categories:

- `error`<br>
  This will cause Psalm to print a message, and to ultimately terminate with a non-zero exit status

- `info`<br>
  This will cause Psalm to print a message
  
- `suppress`<br>
  This will cause Psalm to ignore the code issue entirely

The third category, `suppress`, is the one you will probably be most interested in, especially when introducing Psalm to a large codebase.

## Suppressing issues

There are two ways to suppress an issue – via the Psalm config or via a function docblock.

### Config suppression

You can use the `<issueHandlers>` tag in the config file to influence how issues are treated.

Some issue types allow the use of `referencedMethod`, `referencedClass` or `referencedVariable` to isolate known trouble spots.

```xml
<issueHandlers>
  <MissingPropertyType errorLevel="suppress" /> 

  <InvalidReturnType>
    <errorLevel type="suppress">
      <directory name="some_bad_directory" /> 
      <file name="some_bad_file.php" />  
    </errorLevel>
  </InvalidReturnType>
  <UndefinedMethod>
    <errorLevel type="suppress">
      <referencedMethod name="Bar\Bat::bar" /> 
      <file name="some_bad_file.php" />
    </errorLevel>
  </UndefinedMethod>
  <UndefinedClass>
    <errorLevel type="suppress">
      <referencedClass name="Bar\Bat\Baz" />
    </errorLevel>
  </UndefinedClass>
  <PropertyNotSetInConstructor>
    <errorLevel type="suppress">
        <referencedProperty name="Symfony\Component\Validator\ConstraintValidator::$context" />
    </errorLevel>
  </PropertyNotSetInConstructor>
  <UndefinedGlobalVariable>
    <errorLevel type="suppress">
      <referencedVariable name="$fooBar" /> 
    </errorLevel>
  </UndefinedGlobalVariable>
  <PluginIssue name="IssueNameEmittedByPlugin" errorLevel="info" /> 
</issueHandlers>
```

### Docblock suppression

You can also use `@psalm-suppress IssueName` on a function's docblock to suppress Psalm issues e.g.

```php
<?php
/**
 * @psalm-suppress InvalidReturnType
 */
function (int $a) : string {
  return $a;
}
```

You can also suppress issues at the line level e.g.

```php
<?php
/**
 * @psalm-suppress InvalidReturnType
 */
function (int $a) : string {
  /**
   * @psalm-suppress InvalidReturnStatement
   */
  return $a;
}
```

If you wish to suppress all issues, you can use `@psalm-suppress all` instead of multiple annotations.

The issues listed in [`<unsuppressibleIssues>`](configuration.md#unsuppressibleissues) can't be suppressed, neither this way nor with `<issueHandlers>` or a baseline.

## Using a baseline file

If you have a bunch of errors and you don't want to fix them all at once, Psalm can grandfather-in errors in existing code, while ensuring that new code doesn't have those same sorts of errors.

```
vendor/bin/psalm --set-baseline
```

will generate a file `psalm-baseline.xml` containing the current errors. Alternatively, you can specify the name of your baseline file.

```
vendor/bin/psalm --set-baseline=your-baseline.xml
```

You should commit that generated file so that Psalm can use it when running in other places (e.g. CI). It won't complain about those errors either.

You have two options to use the generated baseline when running psalm:

```
vendor/bin/psalm --use-baseline=your-baseline.xml
```

or using the configuration:

```xml
<?xml version="1.0"?>
<psalm
       ...
       errorBaseline="./path/to/your-baseline.xml"
>
   ...
</psalm>
```

To update that baseline file, use

```
vendor/bin/psalm --update-baseline
```

This will remove fixed issues, but will _not_ add new issues. To add new issues, use `--set-baseline=...`.

In case you want to run psalm without the baseline, run

```
vendor/bin/psalm --ignore-baseline
```

Baseline files are a great way to gradually improve a codebase.

## Using a plugin

If you want something more custom, like suppressing a certain type of error on classes that implement a particular interface, you can use a plugin that implements `AfterClassLikeVisitInterface`

```php
<?php
namespace Foo\Bar;

use Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface;
use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;
use ReflectionClass;

/**
 * Suppress issues dynamically based on interface implementation
 */
class DynamicallySuppressClassIssueBasedOnInterface implements AfterClassLikeVisitInterface
{
    public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event)
    {
        $storage = $event->getStorage();
        if ($storage->user_defined
            && !$storage->is_interface
            && \class_exists($storage->name)
            && (new ReflectionClass($storage->name))->implementsInterface(\Your\Interface::class)
        ) {
            $storage->suppressed_issues[-1] = 'PropertyNotSetInConstructor';
        }
    }
}
```

---

### Running Psalm Error Levels (`docs/running_psalm/error_levels.md`)

# Error levels

Psalm can run at error levels 1 (strictest) through 8 (most lenient). The default is **level 2**.

A stricter level (lower number) reports more issues as errors. A more lenient level (higher number) demotes issues to info (non-blocking).

### Quick-reference summary

| Level | Strictness | What changes compared to the level above |
|-------|-----------|-------------------------------|
| 1 (strictest) | Everything is an error | Adds `Mixed*` issues, `LessSpecificReturnType` as errors |
| **2 (default)** | Most issues | `Mixed*` demoted to info |
| 3 | Moderate | `Deprecated*`, `MissingParamType`, `PropertyNotSetInConstructor` demoted to info |
| 4 | Lenient | `Possibly*` issues demoted to info |
| 5 | More lenient | `InvalidScalarArgument`, `RedundantCondition`, `TooManyArguments` demoted to info |
| 6 | Very lenient | `FalsableReturnStatement`, `InvalidNullableReturnType` demoted to info |
| 7 | Extremely lenient | `InvalidArgument`, `InvalidMethodCall`, `UndefinedMethod` demoted to info |
| 8 (most lenient) | Almost nothing | `MethodSignatureMismatch`, `UninitializedProperty` demoted to info |

### Special categories

- **Always errors**: Issues with very low false-positive rates (e.g., `UndefinedClass`, `UndefinedVariable`). These cannot be suppressed by changing the error level.
- **Feature-specific errors**: Issues only reported when their feature is enabled (e.g., `--taint-analysis` for `Tainted*`, `--find-unused-code` for `Unused*`). When enabled, they are always treated as errors.


## Always treated as errors

These issues have very low false-positive rates and indicate definite problems. They cannot be suppressed by changing the error level.

 - [AbstractMethodCall](issues/AbstractMethodCall.md)
 - [ComplexFunction](issues/ComplexFunction.md)
 - [ComplexMethod](issues/ComplexMethod.md)
 - [ConfigIssue](issues/ConfigIssue.md)
 - [ConstantDeclarationInTrait](issues/ConstantDeclarationInTrait.md)
 - [DuplicateArrayKey](issues/DuplicateArrayKey.md)
 - [DuplicateClass](issues/DuplicateClass.md)
 - [DuplicateConstant](issues/DuplicateConstant.md)
 - [DuplicateEnumCase](issues/DuplicateEnumCase.md)
 - [DuplicateEnumCaseValue](issues/DuplicateEnumCaseValue.md)
 - [DuplicateFunction](issues/DuplicateFunction.md)
 - [DuplicateMethod](issues/DuplicateMethod.md)
 - [DuplicateParam](issues/DuplicateParam.md)
 - [DuplicateProperty](issues/DuplicateProperty.md)
 - [EmptyArrayAccess](issues/EmptyArrayAccess.md)
 - [ExtensionRequirementViolation](issues/ExtensionRequirementViolation.md)
 - [ImplementationRequirementViolation](issues/ImplementationRequirementViolation.md)
 - [ImpureByReferenceAssignment](issues/ImpureByReferenceAssignment.md)
 - [ImpureFunctionCall](issues/ImpureFunctionCall.md)
 - [ImpureGlobalVariable](issues/ImpureGlobalVariable.md)
 - [ImpureMethodCall](issues/ImpureMethodCall.md)
 - [ImpurePropertyAssignment](issues/ImpurePropertyAssignment.md)
 - [ImpurePropertyFetch](issues/ImpurePropertyFetch.md)
 - [ImpureStaticProperty](issues/ImpureStaticProperty.md)
 - [ImpureStaticVariable](issues/ImpureStaticVariable.md)
 - [ImpureVariable](issues/ImpureVariable.md)
 - [InaccessibleClassConstant](issues/InaccessibleClassConstant.md)
 - [InaccessibleMethod](issues/InaccessibleMethod.md)
 - [InaccessibleProperty](issues/InaccessibleProperty.md)
 - [InterfaceInstantiation](issues/InterfaceInstantiation.md)
 - [InvalidAttribute](issues/InvalidAttribute.md)
 - [InvalidEnumBackingType](issues/InvalidEnumBackingType.md)
 - [InvalidEnumCaseValue](issues/InvalidEnumCaseValue.md)
 - [InvalidEnumMethod](issues/InvalidEnumMethod.md)
 - [InvalidExtendClass](issues/InvalidExtendClass.md)
 - [InvalidGlobal](issues/InvalidGlobal.md)
 - [InvalidInterfaceImplementation](issues/InvalidInterfaceImplementation.md)
 - [InvalidParamDefault](issues/InvalidParamDefault.md)
 - [InvalidParent](issues/InvalidParent.md)
 - [InvalidPassByReference](issues/InvalidPassByReference.md)
 - [InvalidScope](issues/InvalidScope.md)
 - [InvalidStaticInvocation](issues/InvalidStaticInvocation.md)
 - [InvalidThrow](issues/InvalidThrow.md)
 - [LoopInvalidation](issues/LoopInvalidation.md)
 - [MethodSignatureMustOmitReturnType](issues/MethodSignatureMustOmitReturnType.md)
 - [MethodSignatureMustProvideReturnType](issues/MethodSignatureMustProvideReturnType.md)
 - [MissingAbstractPureAnnotation](issues/MissingAbstractPureAnnotation.md)
 - [MissingDependency](issues/MissingDependency.md)
 - [MissingFile](issues/MissingFile.md)
 - [MissingImmutableAnnotation](issues/MissingImmutableAnnotation.md)
 - [MissingInterfaceImmutableAnnotation](issues/MissingInterfaceImmutableAnnotation.md)
 - [MissingPureAnnotation](issues/MissingPureAnnotation.md)
 - [MissingTemplateParam](issues/MissingTemplateParam.md)
 - [MissingThrowsDocblock](issues/MissingThrowsDocblock.md)
 - [NoEnumProperties](issues/NoEnumProperties.md)
 - [NoValue](issues/NoValue.md)
 - [NonInvariantPropertyType](issues/NonInvariantPropertyType.md)
 - [NonStaticSelfCall](issues/NonStaticSelfCall.md)
 - [NullArrayAccess](issues/NullArrayAccess.md)
 - [NullFunctionCall](issues/NullFunctionCall.md)
 - [NullIterator](issues/NullIterator.md)
 - [NullPropertyAssignment](issues/NullPropertyAssignment.md)
 - [NullPropertyFetch](issues/NullPropertyFetch.md)
 - [NullReference](issues/NullReference.md)
 - [OverriddenPropertyAccess](issues/OverriddenPropertyAccess.md)
 - [ParadoxicalCondition](issues/ParadoxicalCondition.md)
 - [ParentNotFound](issues/ParentNotFound.md)
 - [TooFewArguments](issues/TooFewArguments.md)
 - [UndefinedAttributeClass](issues/UndefinedAttributeClass.md)
 - [UndefinedClass](issues/UndefinedClass.md)
 - [UndefinedConstant](issues/UndefinedConstant.md)
 - [UndefinedDocblockClass](issues/UndefinedDocblockClass.md)
 - [UndefinedFunction](issues/UndefinedFunction.md)
 - [UndefinedGlobalVariable](issues/UndefinedGlobalVariable.md)
 - [UndefinedInterface](issues/UndefinedInterface.md)
 - [UndefinedTrait](issues/UndefinedTrait.md)
 - [UndefinedVariable](issues/UndefinedVariable.md)
 - [UnimplementedAbstractMethod](issues/UnimplementedAbstractMethod.md)
 - [UnimplementedInterfaceMethod](issues/UnimplementedInterfaceMethod.md)
 - [UnrecognizedExpression](issues/UnrecognizedExpression.md)
 - [UnrecognizedStatement](issues/UnrecognizedStatement.md)
 - [UnresolvableConstant](issues/UnresolvableConstant.md)
 - [UnsupportedPropertyReferenceUsage](issues/UnsupportedPropertyReferenceUsage.md)
 - [UnusedBaselineEntry](issues/UnusedBaselineEntry.md)
 - [UnusedFunctionCall](issues/UnusedFunctionCall.md)
 - [UnusedIssueHandlerSuppression](issues/UnusedIssueHandlerSuppression.md)
 - [UnusedMethodCall](issues/UnusedMethodCall.md)
## Errors that only appear at level 1

At the default level (2), these are reported as info. Set `errorLevel="1"` to treat them as errors.

 - [ImmutableDependency](issues/ImmutableDependency.md)
 - [IncompatibleTypeParameters](issues/IncompatibleTypeParameters.md)
 - [IntMaskComparison](issues/IntMaskComparison.md)
 - [InvalidClassConstantType](issues/InvalidClassConstantType.md)
 - [LessSpecificClassConstantType](issues/LessSpecificClassConstantType.md)
 - [LessSpecificReturnType](issues/LessSpecificReturnType.md)
 - [MixedArgument](issues/MixedArgument.md)
 - [MixedArgumentTypeCoercion](issues/MixedArgumentTypeCoercion.md)
 - [MixedArrayAccess](issues/MixedArrayAccess.md)
 - [MixedArrayAssignment](issues/MixedArrayAssignment.md)
 - [MixedArrayOffset](issues/MixedArrayOffset.md)
 - [MixedArrayTypeCoercion](issues/MixedArrayTypeCoercion.md)
 - [MixedAssignment](issues/MixedAssignment.md)
 - [MixedClone](issues/MixedClone.md)
 - [MixedFunctionCall](issues/MixedFunctionCall.md)
 - [MixedMethodCall](issues/MixedMethodCall.md)
 - [MixedOperand](issues/MixedOperand.md)
 - [MixedPropertyAssignment](issues/MixedPropertyAssignment.md)
 - [MixedPropertyFetch](issues/MixedPropertyFetch.md)
 - [MixedPropertyTypeCoercion](issues/MixedPropertyTypeCoercion.md)
 - [MixedReturnStatement](issues/MixedReturnStatement.md)
 - [MixedReturnTypeCoercion](issues/MixedReturnTypeCoercion.md)
 - [MixedStringOffsetAssignment](issues/MixedStringOffsetAssignment.md)
 - [MutableDependency](issues/MutableDependency.md)
 - [PossiblyNullOperand](issues/PossiblyNullOperand.md)
 - [RedundantFlag](issues/RedundantFlag.md)
 - [RedundantIdentityWithTrue](issues/RedundantIdentityWithTrue.md)
 - [Trace](issues/Trace.md)

## Errors at level 2 and below

These issues become info (non-blocking) at level 3 and higher.

 - [ClassMustBeFinal](issues/ClassMustBeFinal.md)
 - [DeprecatedClass](issues/DeprecatedClass.md)
 - [DeprecatedConstant](issues/DeprecatedConstant.md)
 - [DeprecatedFunction](issues/DeprecatedFunction.md)
 - [DeprecatedInterface](issues/DeprecatedInterface.md)
 - [DeprecatedMethod](issues/DeprecatedMethod.md)
 - [DeprecatedProperty](issues/DeprecatedProperty.md)
 - [DeprecatedTrait](issues/DeprecatedTrait.md)
 - [DirectConstructorCall](issues/DirectConstructorCall.md)
 - [DocblockTypeContradiction](issues/DocblockTypeContradiction.md)
 - [InvalidDocblockParamName](issues/InvalidDocblockParamName.md)
 - [InvalidFalsableReturnType](issues/InvalidFalsableReturnType.md)
 - [InvalidStringClass](issues/InvalidStringClass.md)
 - [MismatchingDocblockPropertyType](issues/MismatchingDocblockPropertyType.md)
 - [MissingClassConstType](issues/MissingClassConstType.md)
 - [MissingClosureParamType](issues/MissingClosureParamType.md)
 - [MissingClosureReturnType](issues/MissingClosureReturnType.md)
 - [MissingConstructor](issues/MissingConstructor.md)
 - [MissingParamType](issues/MissingParamType.md)
 - [MissingPropertyType](issues/MissingPropertyType.md)
 - [MissingReturnType](issues/MissingReturnType.md)
 - [NullOperand](issues/NullOperand.md)
 - [PrivateFinalMethod](issues/PrivateFinalMethod.md)
 - [PropertyNotSetInConstructor](issues/PropertyNotSetInConstructor.md)
 - [RawObjectIteration](issues/RawObjectIteration.md)
 - [RedundantCastGivenDocblockType](issues/RedundantCastGivenDocblockType.md)
 - [RedundantConditionGivenDocblockType](issues/RedundantConditionGivenDocblockType.md)
 - [RedundantFunctionCallGivenDocblockType](issues/RedundantFunctionCallGivenDocblockType.md)
 - [ReferenceConstraintViolation](issues/ReferenceConstraintViolation.md)
 - [RiskyTruthyFalsyComparison](issues/RiskyTruthyFalsyComparison.md)
 - [UndefinedTrace](issues/UndefinedTrace.md)
 - [UnresolvableInclude](issues/UnresolvableInclude.md)
 - [UnsafeGenericInstantiation](issues/UnsafeGenericInstantiation.md)
 - [UnsafeInstantiation](issues/UnsafeInstantiation.md)
 - [UnsupportedReferenceUsage](issues/UnsupportedReferenceUsage.md)

## Errors at level 3 and below

These issues become info (non-blocking) at level 4 and higher.

 - [ArgumentTypeCoercion](issues/ArgumentTypeCoercion.md)
 - [LessSpecificReturnStatement](issues/LessSpecificReturnStatement.md)
 - [MoreSpecificReturnType](issues/MoreSpecificReturnType.md)
 - [NonInvariantDocblockPropertyType](issues/NonInvariantDocblockPropertyType.md)
 - [PossiblyFalseArgument](issues/PossiblyFalseArgument.md)
 - [PossiblyFalseIterator](issues/PossiblyFalseIterator.md)
 - [PossiblyFalseOperand](issues/PossiblyFalseOperand.md)
 - [PossiblyFalsePropertyAssignmentValue](issues/PossiblyFalsePropertyAssignmentValue.md)
 - [PossiblyFalseReference](issues/PossiblyFalseReference.md)
 - [PossiblyInvalidArgument](issues/PossiblyInvalidArgument.md)
 - [PossiblyInvalidArrayAccess](issues/PossiblyInvalidArrayAccess.md)
 - [PossiblyInvalidArrayAssignment](issues/PossiblyInvalidArrayAssignment.md)
 - [PossiblyInvalidArrayOffset](issues/PossiblyInvalidArrayOffset.md)
 - [PossiblyInvalidCast](issues/PossiblyInvalidCast.md)
 - [PossiblyInvalidClone](issues/PossiblyInvalidClone.md)
 - [PossiblyInvalidFunctionCall](issues/PossiblyInvalidFunctionCall.md)
 - [PossiblyInvalidIterator](issues/PossiblyInvalidIterator.md)
 - [PossiblyInvalidMethodCall](issues/PossiblyInvalidMethodCall.md)
 - [PossiblyInvalidOperand](issues/PossiblyInvalidOperand.md)
 - [PossiblyInvalidPropertyAssignment](issues/PossiblyInvalidPropertyAssignment.md)
 - [PossiblyInvalidPropertyAssignmentValue](issues/PossiblyInvalidPropertyAssignmentValue.md)
 - [PossiblyInvalidPropertyFetch](issues/PossiblyInvalidPropertyFetch.md)
 - [PossiblyNullArgument](issues/PossiblyNullArgument.md)
 - [PossiblyNullArrayAccess](issues/PossiblyNullArrayAccess.md)
 - [PossiblyNullArrayAssignment](issues/PossiblyNullArrayAssignment.md)
 - [PossiblyNullArrayOffset](issues/PossiblyNullArrayOffset.md)
 - [PossiblyNullFunctionCall](issues/PossiblyNullFunctionCall.md)
 - [PossiblyNullIterator](issues/PossiblyNullIterator.md)
 - [PossiblyNullPropertyAssignment](issues/PossiblyNullPropertyAssignment.md)
 - [PossiblyNullPropertyAssignmentValue](issues/PossiblyNullPropertyAssignmentValue.md)
 - [PossiblyNullPropertyFetch](issues/PossiblyNullPropertyFetch.md)
 - [PossiblyNullReference](issues/PossiblyNullReference.md)
 - [PossiblyUndefinedArrayOffset](issues/PossiblyUndefinedArrayOffset.md)
 - [PossiblyUndefinedGlobalVariable](issues/PossiblyUndefinedGlobalVariable.md)
 - [PossiblyUndefinedMethod](issues/PossiblyUndefinedMethod.md)
 - [PossiblyUndefinedVariable](issues/PossiblyUndefinedVariable.md)
 - [PropertyTypeCoercion](issues/PropertyTypeCoercion.md)
 - [RiskyCast](issues/RiskyCast.md)

## Errors at level 4 and below

These issues become info (non-blocking) at level 5 and higher.

 - [FalseOperand](issues/FalseOperand.md)
 - [ForbiddenCode](issues/ForbiddenCode.md)
 - [IfThisIsMismatch](issues/IfThisIsMismatch.md)
 - [ImplementedParamTypeMismatch](issues/ImplementedParamTypeMismatch.md)
 - [ImplementedReturnTypeMismatch](issues/ImplementedReturnTypeMismatch.md)
 - [ImplicitToStringCast](issues/ImplicitToStringCast.md)
 - [InheritorViolation](issues/InheritorViolation.md)
 - [InternalClass](issues/InternalClass.md)
 - [InternalMethod](issues/InternalMethod.md)
 - [InternalProperty](issues/InternalProperty.md)
 - [InvalidDocblock](issues/InvalidDocblock.md)
 - [InvalidLiteralArgument](issues/InvalidLiteralArgument.md)
 - [InvalidOperand](issues/InvalidOperand.md)
 - [InvalidScalarArgument](issues/InvalidScalarArgument.md)
 - [InvalidToString](issues/InvalidToString.md)
 - [MismatchingDocblockParamType](issues/MismatchingDocblockParamType.md)
 - [MismatchingDocblockReturnType](issues/MismatchingDocblockReturnType.md)
 - [MissingDocblockType](issues/MissingDocblockType.md)
 - [NoInterfaceProperties](issues/NoInterfaceProperties.md)
 - [PossibleRawObjectIteration](issues/PossibleRawObjectIteration.md)
 - [PossiblyInvalidDocblockTag](issues/PossiblyInvalidDocblockTag.md)
 - [RedundantCast](issues/RedundantCast.md)
 - [RedundantCondition](issues/RedundantCondition.md)
 - [RedundantFunctionCall](issues/RedundantFunctionCall.md)
 - [RedundantPropertyInitializationCheck](issues/RedundantPropertyInitializationCheck.md)
 - [ReferenceReusedFromConfusingScope](issues/ReferenceReusedFromConfusingScope.md)
 - [StringIncrement](issues/StringIncrement.md)
 - [TooManyArguments](issues/TooManyArguments.md)
 - [TypeDoesNotContainNull](issues/TypeDoesNotContainNull.md)
 - [TypeDoesNotContainType](issues/TypeDoesNotContainType.md)
 - [UndefinedMagicMethod](issues/UndefinedMagicMethod.md)
 - [UndefinedMagicPropertyAssignment](issues/UndefinedMagicPropertyAssignment.md)
 - [UndefinedMagicPropertyFetch](issues/UndefinedMagicPropertyFetch.md)

## Errors at level 5 and below

These issues become info (non-blocking) at level 6 and higher.

 - [ConstructorSignatureMismatch](issues/ConstructorSignatureMismatch.md)
 - [FalsableReturnStatement](issues/FalsableReturnStatement.md)
 - [InvalidNullableReturnType](issues/InvalidNullableReturnType.md)
 - [LessSpecificImplementedReturnType](issues/LessSpecificImplementedReturnType.md)
 - [MoreSpecificImplementedParamType](issues/MoreSpecificImplementedParamType.md)
 - [NullableReturnStatement](issues/NullableReturnStatement.md)
 - [UndefinedInterfaceMethod](issues/UndefinedInterfaceMethod.md)
 - [UndefinedThisPropertyAssignment](issues/UndefinedThisPropertyAssignment.md)

## Errors at level 6 and below

These issues become info (non-blocking) at level 7 and higher.

 - [AmbiguousConstantInheritance](issues/AmbiguousConstantInheritance.md)
 - [InvalidArgument](issues/InvalidArgument.md)
 - [InvalidArrayAccess](issues/InvalidArrayAccess.md)
 - [InvalidArrayAssignment](issues/InvalidArrayAssignment.md)
 - [InvalidArrayOffset](issues/InvalidArrayOffset.md)
 - [InvalidCast](issues/InvalidCast.md)
 - [InvalidCatch](issues/InvalidCatch.md)
 - [InvalidClass](issues/InvalidClass.md)
 - [InvalidClone](issues/InvalidClone.md)
 - [InvalidConstantAssignmentValue](issues/InvalidConstantAssignmentValue.md)
 - [InvalidFunctionCall](issues/InvalidFunctionCall.md)
 - [InvalidIterator](issues/InvalidIterator.md)
 - [InvalidMethodCall](issues/InvalidMethodCall.md)
 - [InvalidNamedArgument](issues/InvalidNamedArgument.md)
 - [InvalidPropertyAssignment](issues/InvalidPropertyAssignment.md)
 - [InvalidPropertyAssignmentValue](issues/InvalidPropertyAssignmentValue.md)
 - [InvalidPropertyFetch](issues/InvalidPropertyFetch.md)
 - [InvalidReturnStatement](issues/InvalidReturnStatement.md)
 - [InvalidReturnType](issues/InvalidReturnType.md)
 - [InvalidTemplateParam](issues/InvalidTemplateParam.md)
 - [NullArgument](issues/NullArgument.md)
 - [NullArrayOffset](issues/NullArrayOffset.md)
 - [OverriddenFinalConstant](issues/OverriddenFinalConstant.md)
 - [OverriddenFinalProperty](issues/OverriddenFinalProperty.md)
 - [OverriddenInterfaceConstant](issues/OverriddenInterfaceConstant.md)
 - [TooManyTemplateParams](issues/TooManyTemplateParams.md)
 - [TraitMethodSignatureMismatch](issues/TraitMethodSignatureMismatch.md)
 - [UndefinedMethod](issues/UndefinedMethod.md)
 - [UndefinedPropertyAssignment](issues/UndefinedPropertyAssignment.md)
 - [UndefinedPropertyFetch](issues/UndefinedPropertyFetch.md)
 - [UndefinedThisPropertyFetch](issues/UndefinedThisPropertyFetch.md)

## Errors at level 7 and below

These issues become info (non-blocking) at level 8.

 - [AbstractInstantiation](issues/AbstractInstantiation.md)
 - [AssignmentToVoid](issues/AssignmentToVoid.md)
 - [CircularReference](issues/CircularReference.md)
 - [ConflictingReferenceConstraint](issues/ConflictingReferenceConstraint.md)
 - [ContinueOutsideLoop](issues/ContinueOutsideLoop.md)
 - [InvalidOverride](issues/InvalidOverride.md)
 - [InvalidTraversableImplementation](issues/InvalidTraversableImplementation.md)
 - [InvalidTypeImport](issues/InvalidTypeImport.md)
 - [MethodSignatureMismatch](issues/MethodSignatureMismatch.md)
 - [NamedArgumentNotAllowed](issues/NamedArgumentNotAllowed.md)
 - [NonVariableReferenceReturn](issues/NonVariableReferenceReturn.md)
 - [OverriddenMethodAccess](issues/OverriddenMethodAccess.md)
 - [ParamNameMismatch](issues/ParamNameMismatch.md)
 - [ReservedWord](issues/ReservedWord.md)
 - [UnhandledMatchCondition](issues/UnhandledMatchCondition.md)
 - [UninitializedProperty](issues/UninitializedProperty.md)

## Feature-specific errors

These issues are only reported when their corresponding feature is enabled (e.g., `--taint-analysis` for Tainted* issues, `--find-unused-code` for Unused* issues). When enabled, they are always treated as errors.

 - [LiteralKeyUnshapedArray](issues/LiteralKeyUnshapedArray.md)
 - [MissingOverrideAttribute](issues/MissingOverrideAttribute.md)
 - [PossiblyUndefinedIntArrayOffset](issues/PossiblyUndefinedIntArrayOffset.md)
 - [PossiblyUndefinedStringArrayOffset](issues/PossiblyUndefinedStringArrayOffset.md)
 - [PossiblyUnusedMethod](issues/PossiblyUnusedMethod.md)
 - [PossiblyUnusedParam](issues/PossiblyUnusedParam.md)
 - [PossiblyUnusedProperty](issues/PossiblyUnusedProperty.md)
 - [PossiblyUnusedReturnValue](issues/PossiblyUnusedReturnValue.md)
 - [TaintedCallable](issues/TaintedCallable.md)
 - [TaintedCookie](issues/TaintedCookie.md)
 - [TaintedCustom](issues/TaintedCustom.md)
 - [TaintedEval](issues/TaintedEval.md)
 - [TaintedExtract](issues/TaintedExtract.md)
 - [TaintedFile](issues/TaintedFile.md)
 - [TaintedHeader](issues/TaintedHeader.md)
 - [TaintedHtml](issues/TaintedHtml.md)
 - [TaintedInclude](issues/TaintedInclude.md)
 - [TaintedInput](issues/TaintedInput.md)
 - [TaintedLdap](issues/TaintedLdap.md)
 - [TaintedLlmPrompt](issues/TaintedLlmPrompt.md)
 - [TaintedNosql](issues/TaintedNosql.md)
 - [TaintedSSRF](issues/TaintedSSRF.md)
 - [TaintedShell](issues/TaintedShell.md)
 - [TaintedSleep](issues/TaintedSleep.md)
 - [TaintedSql](issues/TaintedSql.md)
 - [TaintedSystemSecret](issues/TaintedSystemSecret.md)
 - [TaintedTextWithQuotes](issues/TaintedTextWithQuotes.md)
 - [TaintedUnserialize](issues/TaintedUnserialize.md)
 - [TaintedUrlComponent](issues/TaintedUrlComponent.md)
 - [TaintedUrlPath](issues/TaintedUrlPath.md)
 - [TaintedUserSecret](issues/TaintedUserSecret.md)
 - [TaintedXpath](issues/TaintedXpath.md)
 - [UncaughtThrowInGlobalScope](issues/UncaughtThrowInGlobalScope.md)
 - [UnevaluatedCode](issues/UnevaluatedCode.md)
 - [UnnecessaryVarAnnotation](issues/UnnecessaryVarAnnotation.md)
 - [UnusedClass](issues/UnusedClass.md)
 - [UnusedClosureParam](issues/UnusedClosureParam.md)
 - [UnusedConstructor](issues/UnusedConstructor.md)
 - [UnusedDocblockParam](issues/UnusedDocblockParam.md)
 - [UnusedForeachValue](issues/UnusedForeachValue.md)
 - [UnusedMethod](issues/UnusedMethod.md)
 - [UnusedParam](issues/UnusedParam.md)
 - [UnusedProperty](issues/UnusedProperty.md)
 - [UnusedPsalmSuppress](issues/UnusedPsalmSuppress.md)
 - [UnusedReturnValue](issues/UnusedReturnValue.md)
 - [UnusedVariable](issues/UnusedVariable.md)

---

### Running Psalm Installation (`docs/running_psalm/installation.md`)

# Installation

The latest version of Psalm requires PHP >= 8.2 and [Composer](https://getcomposer.org/).

```bash
composer require --dev vimeo/psalm
```

Generate a config file:

```bash
./vendor/bin/psalm --init
```

Psalm will scan your project and figure out an appropriate [error level](error_levels.md) for your codebase.

Then run Psalm:

```bash
./vendor/bin/psalm --no-cache
```

Psalm will probably find a number of issues - find out how to deal with them in [Dealing with code issues](dealing_with_code_issues.md).

## Docker image

It is recommended to run Psalm in the official docker image: it uses a custom build of PHP built from scratch, running Psalm **+30% faster** on average than normal PHP (**+50% faster** if comparing to PHP without opcache installed).  

```bash
docker run -v $PWD:/app --rm -it ghcr.io/danog/psalm:latest /composer/vendor/bin/psalm --no-cache
```

More specific tags are also available (i.e. `ghcr.io/danog/psalm:6.9.1`, as well as branch tags).   

Issues due to missing extensions can be fixed by enabling them in psalm.xml and/or requiring them in composer.json [see here &raquo;](https://psalm.dev/docs/running_psalm/configuration/#enableextensions) for more info.

Extensions not stubbed by Psalm itself (and thus not available as a psalm config option) may be stubbed using [traditional PHP stubs](https://github.com/JetBrains/phpstorm-stubs/).

## Installing plugins

While Psalm can figure out the types used by various libraries based on
their source code and docblocks, it works even better with custom-tailored types
provided by Psalm plugins.

Check out the [list of existing plugins on Packagist](https://packagist.org/?type=psalm-plugin). 
Install them with `composer require --dev <plugin/package> && vendor/bin/psalm-plugin enable <plugin/package>`

Read more about plugins in [Using Plugins chapter](plugins/using_plugins.md).

## Using the Phar

Sometimes your project can conflict with one or more of Psalm’s dependencies. In
that case you may find the Phar (a self-contained PHP executable) useful.

The Phar can be downloaded from GitHub:

```bash
wget https://github.com/vimeo/psalm/releases/latest/download/psalm.phar
chmod +x psalm.phar
./psalm.phar --version
```

Alternatively, you can use Composer to install the Phar:

```bash
composer require --dev psalm/phar
```

---

### Running Psalm Issues (`docs/running_psalm/issues.md`)

# Issue types

 - [AbstractInstantiation](issues/AbstractInstantiation.md)
 - [AbstractMethodCall](issues/AbstractMethodCall.md)
 - [AmbiguousConstantInheritance](issues/AmbiguousConstantInheritance.md)
 - [ArgumentTypeCoercion](issues/ArgumentTypeCoercion.md)
 - [AssignmentToVoid](issues/AssignmentToVoid.md)
 - [CheckType](issues/CheckType.md)
 - [CircularReference](issues/CircularReference.md)
 - [ClassMustBeFinal](issues/ClassMustBeFinal.md)
 - [ComplexFunction](issues/ComplexFunction.md)
 - [ComplexMethod](issues/ComplexMethod.md)
 - [ConfigIssue](issues/ConfigIssue.md)
 - [ConflictingReferenceConstraint](issues/ConflictingReferenceConstraint.md)
 - [ConstantDeclarationInTrait](issues/ConstantDeclarationInTrait.md)
 - [ConstructorSignatureMismatch](issues/ConstructorSignatureMismatch.md)
 - [ContinueOutsideLoop](issues/ContinueOutsideLoop.md)
 - [DeprecatedClass](issues/DeprecatedClass.md)
 - [DeprecatedConstant](issues/DeprecatedConstant.md)
 - [DeprecatedFunction](issues/DeprecatedFunction.md)
 - [DeprecatedInterface](issues/DeprecatedInterface.md)
 - [DeprecatedMethod](issues/DeprecatedMethod.md)
 - [DeprecatedProperty](issues/DeprecatedProperty.md)
 - [DeprecatedTrait](issues/DeprecatedTrait.md)
 - [DirectConstructorCall](issues/DirectConstructorCall.md)
 - [DocblockTypeContradiction](issues/DocblockTypeContradiction.md)
 - [DuplicateArrayKey](issues/DuplicateArrayKey.md)
 - [DuplicateClass](issues/DuplicateClass.md)
 - [DuplicateConstant](issues/DuplicateConstant.md)
 - [DuplicateEnumCase](issues/DuplicateEnumCase.md)
 - [DuplicateEnumCaseValue](issues/DuplicateEnumCaseValue.md)
 - [DuplicateFunction](issues/DuplicateFunction.md)
 - [DuplicateMethod](issues/DuplicateMethod.md)
 - [DuplicateParam](issues/DuplicateParam.md)
 - [DuplicateProperty](issues/DuplicateProperty.md)
 - [EmptyArrayAccess](issues/EmptyArrayAccess.md)
 - [ExtensionRequirementViolation](issues/ExtensionRequirementViolation.md)
 - [FalsableReturnStatement](issues/FalsableReturnStatement.md)
 - [FalseOperand](issues/FalseOperand.md)
 - [ForbiddenCode](issues/ForbiddenCode.md)
 - [IfThisIsMismatch](issues/IfThisIsMismatch.md)
 - [ImmutableDependency](issues/ImmutableDependency.md)
 - [ImplementationRequirementViolation](issues/ImplementationRequirementViolation.md)
 - [ImplementedParamTypeMismatch](issues/ImplementedParamTypeMismatch.md)
 - [ImplementedReturnTypeMismatch](issues/ImplementedReturnTypeMismatch.md)
 - [ImplicitToStringCast](issues/ImplicitToStringCast.md)
 - [ImpureByReferenceAssignment](issues/ImpureByReferenceAssignment.md)
 - [ImpureFunctionCall](issues/ImpureFunctionCall.md)
 - [ImpureGlobalVariable](issues/ImpureGlobalVariable.md)
 - [ImpureMethodCall](issues/ImpureMethodCall.md)
 - [ImpurePropertyAssignment](issues/ImpurePropertyAssignment.md)
 - [ImpurePropertyFetch](issues/ImpurePropertyFetch.md)
 - [ImpureStaticProperty](issues/ImpureStaticProperty.md)
 - [ImpureStaticVariable](issues/ImpureStaticVariable.md)
 - [ImpureVariable](issues/ImpureVariable.md)
 - [InaccessibleClassConstant](issues/InaccessibleClassConstant.md)
 - [InaccessibleMethod](issues/InaccessibleMethod.md)
 - [InaccessibleProperty](issues/InaccessibleProperty.md)
 - [IncompatibleTypeParameters](issues/IncompatibleTypeParameters.md)
 - [InheritorViolation](issues/InheritorViolation.md)
 - [InterfaceInstantiation](issues/InterfaceInstantiation.md)
 - [InternalClass](issues/InternalClass.md)
 - [InternalMethod](issues/InternalMethod.md)
 - [InternalProperty](issues/InternalProperty.md)
 - [IntMaskComparison](issues/IntMaskComparison.md)
 - [InvalidArgument](issues/InvalidArgument.md)
 - [InvalidArrayAccess](issues/InvalidArrayAccess.md)
 - [InvalidArrayAssignment](issues/InvalidArrayAssignment.md)
 - [InvalidArrayOffset](issues/InvalidArrayOffset.md)
 - [InvalidAttribute](issues/InvalidAttribute.md)
 - [InvalidCast](issues/InvalidCast.md)
 - [InvalidCatch](issues/InvalidCatch.md)
 - [InvalidClass](issues/InvalidClass.md)
 - [InvalidClassConstantType](issues/InvalidClassConstantType.md)
 - [InvalidClone](issues/InvalidClone.md)
 - [InvalidConstantAssignmentValue](issues/InvalidConstantAssignmentValue.md)
 - [InvalidDocblock](issues/InvalidDocblock.md)
 - [InvalidDocblockParamName](issues/InvalidDocblockParamName.md)
 - [InvalidEnumBackingType](issues/InvalidEnumBackingType.md)
 - [InvalidEnumCaseValue](issues/InvalidEnumCaseValue.md)
 - [InvalidEnumMethod](issues/InvalidEnumMethod.md)
 - [InvalidExtendClass](issues/InvalidExtendClass.md)
 - [InvalidFalsableReturnType](issues/InvalidFalsableReturnType.md)
 - [InvalidFunctionCall](issues/InvalidFunctionCall.md)
 - [InvalidGlobal](issues/InvalidGlobal.md)
 - [InvalidInterfaceImplementation](issues/InvalidInterfaceImplementation.md)
 - [InvalidIterator](issues/InvalidIterator.md)
 - [InvalidLiteralArgument](issues/InvalidLiteralArgument.md)
 - [InvalidMethodCall](issues/InvalidMethodCall.md)
 - [InvalidNamedArgument](issues/InvalidNamedArgument.md)
 - [InvalidNullableReturnType](issues/InvalidNullableReturnType.md)
 - [InvalidOperand](issues/InvalidOperand.md)
 - [InvalidOverride](issues/InvalidOverride.md)
 - [InvalidParamDefault](issues/InvalidParamDefault.md)
 - [InvalidParent](issues/InvalidParent.md)
 - [InvalidPassByReference](issues/InvalidPassByReference.md)
 - [InvalidPropertyAssignment](issues/InvalidPropertyAssignment.md)
 - [InvalidPropertyAssignmentValue](issues/InvalidPropertyAssignmentValue.md)
 - [InvalidPropertyFetch](issues/InvalidPropertyFetch.md)
 - [InvalidReturnStatement](issues/InvalidReturnStatement.md)
 - [InvalidReturnType](issues/InvalidReturnType.md)
 - [InvalidScalarArgument](issues/InvalidScalarArgument.md)
 - [InvalidScope](issues/InvalidScope.md)
 - [InvalidStaticInvocation](issues/InvalidStaticInvocation.md)
 - [InvalidStringClass](issues/InvalidStringClass.md)
 - [InvalidTemplateParam](issues/InvalidTemplateParam.md)
 - [InvalidThrow](issues/InvalidThrow.md)
 - [InvalidToString](issues/InvalidToString.md)
 - [InvalidTraversableImplementation](issues/InvalidTraversableImplementation.md)
 - [InvalidTypeImport](issues/InvalidTypeImport.md)
 - [LessSpecificClassConstantType](issues/LessSpecificClassConstantType.md)
 - [LessSpecificImplementedReturnType](issues/LessSpecificImplementedReturnType.md)
 - [LessSpecificReturnStatement](issues/LessSpecificReturnStatement.md)
 - [LessSpecificReturnType](issues/LessSpecificReturnType.md)
 - [LiteralKeyUnshapedArray](issues/LiteralKeyUnshapedArray.md)
 - [LoopInvalidation](issues/LoopInvalidation.md)
 - [MethodSignatureMismatch](issues/MethodSignatureMismatch.md)
 - [MethodSignatureMustOmitReturnType](issues/MethodSignatureMustOmitReturnType.md)
 - [MethodSignatureMustProvideReturnType](issues/MethodSignatureMustProvideReturnType.md)
 - [MismatchingDocblockParamType](issues/MismatchingDocblockParamType.md)
 - [MismatchingDocblockPropertyType](issues/MismatchingDocblockPropertyType.md)
 - [MismatchingDocblockReturnType](issues/MismatchingDocblockReturnType.md)
 - [MissingAbstractPureAnnotation](issues/MissingAbstractPureAnnotation.md)
 - [MissingClassConstType](issues/MissingClassConstType.md)
 - [MissingClosureParamType](issues/MissingClosureParamType.md)
 - [MissingClosureReturnType](issues/MissingClosureReturnType.md)
 - [MissingConstructor](issues/MissingConstructor.md)
 - [MissingDependency](issues/MissingDependency.md)
 - [MissingDocblockType](issues/MissingDocblockType.md)
 - [MissingFile](issues/MissingFile.md)
 - [MissingImmutableAnnotation](issues/MissingImmutableAnnotation.md)
 - [MissingInterfaceImmutableAnnotation](issues/MissingInterfaceImmutableAnnotation.md)
 - [MissingOverrideAttribute](issues/MissingOverrideAttribute.md)
 - [MissingParamType](issues/MissingParamType.md)
 - [MissingPropertyType](issues/MissingPropertyType.md)
 - [MissingPureAnnotation](issues/MissingPureAnnotation.md)
 - [MissingReturnType](issues/MissingReturnType.md)
 - [MissingTemplateParam](issues/MissingTemplateParam.md)
 - [MissingThrowsDocblock](issues/MissingThrowsDocblock.md)
 - [MixedArgument](issues/MixedArgument.md)
 - [MixedArgumentTypeCoercion](issues/MixedArgumentTypeCoercion.md)
 - [MixedArrayAccess](issues/MixedArrayAccess.md)
 - [MixedArrayAssignment](issues/MixedArrayAssignment.md)
 - [MixedArrayOffset](issues/MixedArrayOffset.md)
 - [MixedArrayTypeCoercion](issues/MixedArrayTypeCoercion.md)
 - [MixedAssignment](issues/MixedAssignment.md)
 - [MixedClone](issues/MixedClone.md)
 - [MixedFunctionCall](issues/MixedFunctionCall.md)
 - [MixedMethodCall](issues/MixedMethodCall.md)
 - [MixedOperand](issues/MixedOperand.md)
 - [MixedPropertyAssignment](issues/MixedPropertyAssignment.md)
 - [MixedPropertyFetch](issues/MixedPropertyFetch.md)
 - [MixedPropertyTypeCoercion](issues/MixedPropertyTypeCoercion.md)
 - [MixedReturnStatement](issues/MixedReturnStatement.md)
 - [MixedReturnTypeCoercion](issues/MixedReturnTypeCoercion.md)
 - [MixedStringOffsetAssignment](issues/MixedStringOffsetAssignment.md)
 - [MoreSpecificImplementedParamType](issues/MoreSpecificImplementedParamType.md)
 - [MoreSpecificReturnType](issues/MoreSpecificReturnType.md)
 - [MutableDependency](issues/MutableDependency.md)
 - [NamedArgumentNotAllowed](issues/NamedArgumentNotAllowed.md)
 - [NoEnumProperties](issues/NoEnumProperties.md)
 - [NoInterfaceProperties](issues/NoInterfaceProperties.md)
 - [NonInvariantDocblockPropertyType](issues/NonInvariantDocblockPropertyType.md)
 - [NonInvariantPropertyType](issues/NonInvariantPropertyType.md)
 - [NonStaticSelfCall](issues/NonStaticSelfCall.md)
 - [NonVariableReferenceReturn](issues/NonVariableReferenceReturn.md)
 - [NoValue](issues/NoValue.md)
 - [NullableReturnStatement](issues/NullableReturnStatement.md)
 - [NullArgument](issues/NullArgument.md)
 - [NullArrayAccess](issues/NullArrayAccess.md)
 - [NullArrayOffset](issues/NullArrayOffset.md)
 - [NullFunctionCall](issues/NullFunctionCall.md)
 - [NullIterator](issues/NullIterator.md)
 - [NullOperand](issues/NullOperand.md)
 - [NullPropertyAssignment](issues/NullPropertyAssignment.md)
 - [NullPropertyFetch](issues/NullPropertyFetch.md)
 - [NullReference](issues/NullReference.md)
 - [OverriddenFinalConstant](issues/OverriddenFinalConstant.md)
 - [OverriddenFinalProperty](issues/OverriddenFinalProperty.md)
 - [OverriddenInterfaceConstant](issues/OverriddenInterfaceConstant.md)
 - [OverriddenMethodAccess](issues/OverriddenMethodAccess.md)
 - [OverriddenPropertyAccess](issues/OverriddenPropertyAccess.md)
 - [ParadoxicalCondition](issues/ParadoxicalCondition.md)
 - [ParamNameMismatch](issues/ParamNameMismatch.md)
 - [ParentNotFound](issues/ParentNotFound.md)
 - [ParseError](issues/ParseError.md)
 - [PluginIssue](issues/PluginIssue.md)
 - [PossibleRawObjectIteration](issues/PossibleRawObjectIteration.md)
 - [PossiblyFalseArgument](issues/PossiblyFalseArgument.md)
 - [PossiblyFalseIterator](issues/PossiblyFalseIterator.md)
 - [PossiblyFalseOperand](issues/PossiblyFalseOperand.md)
 - [PossiblyFalsePropertyAssignmentValue](issues/PossiblyFalsePropertyAssignmentValue.md)
 - [PossiblyFalseReference](issues/PossiblyFalseReference.md)
 - [PossiblyInvalidArgument](issues/PossiblyInvalidArgument.md)
 - [PossiblyInvalidArrayAccess](issues/PossiblyInvalidArrayAccess.md)
 - [PossiblyInvalidArrayAssignment](issues/PossiblyInvalidArrayAssignment.md)
 - [PossiblyInvalidArrayOffset](issues/PossiblyInvalidArrayOffset.md)
 - [PossiblyInvalidCast](issues/PossiblyInvalidCast.md)
 - [PossiblyInvalidClone](issues/PossiblyInvalidClone.md)
 - [PossiblyInvalidDocblockTag](issues/PossiblyInvalidDocblockTag.md)
 - [PossiblyInvalidFunctionCall](issues/PossiblyInvalidFunctionCall.md)
 - [PossiblyInvalidIterator](issues/PossiblyInvalidIterator.md)
 - [PossiblyInvalidMethodCall](issues/PossiblyInvalidMethodCall.md)
 - [PossiblyInvalidOperand](issues/PossiblyInvalidOperand.md)
 - [PossiblyInvalidPropertyAssignment](issues/PossiblyInvalidPropertyAssignment.md)
 - [PossiblyInvalidPropertyAssignmentValue](issues/PossiblyInvalidPropertyAssignmentValue.md)
 - [PossiblyInvalidPropertyFetch](issues/PossiblyInvalidPropertyFetch.md)
 - [PossiblyNullArgument](issues/PossiblyNullArgument.md)
 - [PossiblyNullArrayAccess](issues/PossiblyNullArrayAccess.md)
 - [PossiblyNullArrayAssignment](issues/PossiblyNullArrayAssignment.md)
 - [PossiblyNullArrayOffset](issues/PossiblyNullArrayOffset.md)
 - [PossiblyNullFunctionCall](issues/PossiblyNullFunctionCall.md)
 - [PossiblyNullIterator](issues/PossiblyNullIterator.md)
 - [PossiblyNullOperand](issues/PossiblyNullOperand.md)
 - [PossiblyNullPropertyAssignment](issues/PossiblyNullPropertyAssignment.md)
 - [PossiblyNullPropertyAssignmentValue](issues/PossiblyNullPropertyAssignmentValue.md)
 - [PossiblyNullPropertyFetch](issues/PossiblyNullPropertyFetch.md)
 - [PossiblyNullReference](issues/PossiblyNullReference.md)
 - [PossiblyUndefinedArrayOffset](issues/PossiblyUndefinedArrayOffset.md)
 - [PossiblyUndefinedGlobalVariable](issues/PossiblyUndefinedGlobalVariable.md)
 - [PossiblyUndefinedIntArrayOffset](issues/PossiblyUndefinedIntArrayOffset.md)
 - [PossiblyUndefinedMethod](issues/PossiblyUndefinedMethod.md)
 - [PossiblyUndefinedStringArrayOffset](issues/PossiblyUndefinedStringArrayOffset.md)
 - [PossiblyUndefinedVariable](issues/PossiblyUndefinedVariable.md)
 - [PossiblyUnusedMethod](issues/PossiblyUnusedMethod.md)
 - [PossiblyUnusedParam](issues/PossiblyUnusedParam.md)
 - [PossiblyUnusedProperty](issues/PossiblyUnusedProperty.md)
 - [PossiblyUnusedReturnValue](issues/PossiblyUnusedReturnValue.md)
 - [PrivateFinalMethod](issues/PrivateFinalMethod.md)
 - [PropertyNotSetInConstructor](issues/PropertyNotSetInConstructor.md)
 - [PropertyTypeCoercion](issues/PropertyTypeCoercion.md)
 - [RawObjectIteration](issues/RawObjectIteration.md)
 - [RedundantCast](issues/RedundantCast.md)
 - [RedundantCastGivenDocblockType](issues/RedundantCastGivenDocblockType.md)
 - [RedundantCondition](issues/RedundantCondition.md)
 - [RedundantConditionGivenDocblockType](issues/RedundantConditionGivenDocblockType.md)
 - [RedundantFlag](issues/RedundantFlag.md)
 - [RedundantFunctionCall](issues/RedundantFunctionCall.md)
 - [RedundantFunctionCallGivenDocblockType](issues/RedundantFunctionCallGivenDocblockType.md)
 - [RedundantIdentityWithTrue](issues/RedundantIdentityWithTrue.md)
 - [RedundantPropertyInitializationCheck](issues/RedundantPropertyInitializationCheck.md)
 - [ReferenceConstraintViolation](issues/ReferenceConstraintViolation.md)
 - [ReferenceReusedFromConfusingScope](issues/ReferenceReusedFromConfusingScope.md)
 - [ReservedWord](issues/ReservedWord.md)
 - [RiskyCast](issues/RiskyCast.md)
 - [RiskyTruthyFalsyComparison](issues/RiskyTruthyFalsyComparison.md)
 - [StringIncrement](issues/StringIncrement.md)
 - [TaintedCallable](issues/TaintedCallable.md)
 - [TaintedCookie](issues/TaintedCookie.md)
 - [TaintedCustom](issues/TaintedCustom.md)
 - [TaintedEval](issues/TaintedEval.md)
 - [TaintedExtract](issues/TaintedExtract.md)
 - [TaintedFile](issues/TaintedFile.md)
 - [TaintedHeader](issues/TaintedHeader.md)
 - [TaintedHtml](issues/TaintedHtml.md)
 - [TaintedInclude](issues/TaintedInclude.md)
 - [TaintedInput](issues/TaintedInput.md)
 - [TaintedLdap](issues/TaintedLdap.md)
 - [TaintedLlmPrompt](issues/TaintedLlmPrompt.md)
 - [TaintedNosql](issues/TaintedNosql.md)
 - [TaintedShell](issues/TaintedShell.md)
 - [TaintedSleep](issues/TaintedSleep.md)
 - [TaintedSql](issues/TaintedSql.md)
 - [TaintedSSRF](issues/TaintedSSRF.md)
 - [TaintedSystemSecret](issues/TaintedSystemSecret.md)
 - [TaintedTextWithQuotes](issues/TaintedTextWithQuotes.md)
 - [TaintedUnserialize](issues/TaintedUnserialize.md)
 - [TaintedUrlComponent](issues/TaintedUrlComponent.md)
 - [TaintedUrlPath](issues/TaintedUrlPath.md)
 - [TaintedUserSecret](issues/TaintedUserSecret.md)
 - [TaintedXpath](issues/TaintedXpath.md)
 - [TooFewArguments](issues/TooFewArguments.md)
 - [TooManyArguments](issues/TooManyArguments.md)
 - [TooManyTemplateParams](issues/TooManyTemplateParams.md)
 - [Trace](issues/Trace.md)
 - [TraitMethodSignatureMismatch](issues/TraitMethodSignatureMismatch.md)
 - [TypeDoesNotContainNull](issues/TypeDoesNotContainNull.md)
 - [TypeDoesNotContainType](issues/TypeDoesNotContainType.md)
 - [UncaughtThrowInGlobalScope](issues/UncaughtThrowInGlobalScope.md)
 - [UndefinedAttributeClass](issues/UndefinedAttributeClass.md)
 - [UndefinedClass](issues/UndefinedClass.md)
 - [UndefinedConstant](issues/UndefinedConstant.md)
 - [UndefinedDocblockClass](issues/UndefinedDocblockClass.md)
 - [UndefinedFunction](issues/UndefinedFunction.md)
 - [UndefinedGlobalVariable](issues/UndefinedGlobalVariable.md)
 - [UndefinedInterface](issues/UndefinedInterface.md)
 - [UndefinedInterfaceMethod](issues/UndefinedInterfaceMethod.md)
 - [UndefinedMagicMethod](issues/UndefinedMagicMethod.md)
 - [UndefinedMagicPropertyAssignment](issues/UndefinedMagicPropertyAssignment.md)
 - [UndefinedMagicPropertyFetch](issues/UndefinedMagicPropertyFetch.md)
 - [UndefinedMethod](issues/UndefinedMethod.md)
 - [UndefinedPropertyAssignment](issues/UndefinedPropertyAssignment.md)
 - [UndefinedPropertyFetch](issues/UndefinedPropertyFetch.md)
 - [UndefinedThisPropertyAssignment](issues/UndefinedThisPropertyAssignment.md)
 - [UndefinedThisPropertyFetch](issues/UndefinedThisPropertyFetch.md)
 - [UndefinedTrace](issues/UndefinedTrace.md)
 - [UndefinedTrait](issues/UndefinedTrait.md)
 - [UndefinedVariable](issues/UndefinedVariable.md)
 - [UnevaluatedCode](issues/UnevaluatedCode.md)
 - [UnhandledMatchCondition](issues/UnhandledMatchCondition.md)
 - [UnimplementedAbstractMethod](issues/UnimplementedAbstractMethod.md)
 - [UnimplementedInterfaceMethod](issues/UnimplementedInterfaceMethod.md)
 - [UninitializedProperty](issues/UninitializedProperty.md)
 - [UnnecessaryVarAnnotation](issues/UnnecessaryVarAnnotation.md)
 - [UnrecognizedExpression](issues/UnrecognizedExpression.md)
 - [UnrecognizedStatement](issues/UnrecognizedStatement.md)
 - [UnresolvableConstant](issues/UnresolvableConstant.md)
 - [UnresolvableInclude](issues/UnresolvableInclude.md)
 - [UnsafeGenericInstantiation](issues/UnsafeGenericInstantiation.md)
 - [UnsafeInstantiation](issues/UnsafeInstantiation.md)
 - [UnsupportedPropertyReferenceUsage](issues/UnsupportedPropertyReferenceUsage.md)
 - [UnsupportedReferenceUsage](issues/UnsupportedReferenceUsage.md)
 - [UnusedBaselineEntry](issues/UnusedBaselineEntry.md)
 - [UnusedClass](issues/UnusedClass.md)
 - [UnusedClosureParam](issues/UnusedClosureParam.md)
 - [UnusedConstructor](issues/UnusedConstructor.md)
 - [UnusedDocblockParam](issues/UnusedDocblockParam.md)
 - [UnusedForeachValue](issues/UnusedForeachValue.md)
 - [UnusedFunctionCall](issues/UnusedFunctionCall.md)
 - [UnusedIssueHandlerSuppression](issues/UnusedIssueHandlerSuppression.md)
 - [UnusedMethod](issues/UnusedMethod.md)
 - [UnusedMethodCall](issues/UnusedMethodCall.md)
 - [UnusedParam](issues/UnusedParam.md)
 - [UnusedProperty](issues/UnusedProperty.md)
 - [UnusedPsalmSuppress](issues/UnusedPsalmSuppress.md)
 - [UnusedReturnValue](issues/UnusedReturnValue.md)
 - [UnusedVariable](issues/UnusedVariable.md)

---

### Running Psalm Language Server (`docs/running_psalm/language_server.md`)

# Using Psalm’s Language Server

Psalm now has built-in Language Server Compatibility support so you can run it in your favourite IDE.

It currently supports diagnostics (i.e. finding errors and warnings), go-to-definition and hover, with limited support for autocompletion (PRs are welcome!).

It works well in a variety of editors (listed alphabetically):

## Client configuration

### Emacs

I got it working with [eglot](https://github.com/joaotavora/eglot)

This is the config I used:

```
(when (file-exists-p "vendor/bin/psalm-language-server")
  (progn
    (require 'php-mode)
    (require 'eglot)
    (add-to-list 'eglot-server-programs '(php-mode . ("php" "vendor/bin/psalm-language-server")))
    (add-hook 'php-mode-hook 'eglot-ensure)
    (advice-add 'eglot-eldoc-function :around
                (lambda (oldfun)
                  (let ((help (help-at-pt-kbd-string)))
                    (if help (message "%s" help) (funcall oldfun)))))
    )
  )
```

### PhpStorm

#### Native Support

As of PhpStorm 2020.3 support for psalm is supported and on by default, you can read more about that [here](https://www.jetbrains.com/help/phpstorm/using-psalm.html)

#### With LSP

Alternatively, psalm works with `gtache/intellij-lsp` plugin ([Jetbrains-approved version](https://plugins.jetbrains.com/plugin/10209-lsp-support), [latest version](https://github.com/gtache/intellij-lsp/releases/tag/v1.6.0)).

Setup is done via a GUI.

When you install the plugin, you should see a "Language Server Protocol" section under the "Languages & Frameworks" tab.

In the "Server definitions" tab you should add a definition for Psalm:

 - Select `Executable`
 - Extension: `php`
 - Path: `<path-to-php-binary>` e.g. `/usr/local/bin/php` or `C:\php\php.exe`
     - this should be an absolute path, not just `php`
 - Args: `vendor/bin/psalm-language-server` (on Windows use `vendor/vimeo/psalm/psalm-language-server`, or for a 'global' install '%APPDATA%' + `\Composer\vendor\vimeo\psalm\psalm-language-server`, where the '%APPDATA%' environment variable is probably something like `C:\Users\<homedir>\AppData\Roaming\`)

In the "Timeouts" tab you can adjust the initialization timeout. This is important if you have a large project. You should set the "Init" value to the number of milliseconds you allow Psalm to scan your entire project and your project's dependencies. For opening a couple of projects that use large PHP frameworks, on a high-end business laptop, try `240000` milliseconds for Init.

### Sublime Text

I use the excellent Sublime [LSP plugin](https://github.com/tomv564/LSP) with the following config(Package Settings > LSP > Settings):
```json
    "clients": {
        "psalm": {
            "command": ["php", "vendor/bin/psalm-language-server"],
            "selector": "source.php | embedding.php",
            "enabled": true
        }
    }
```

### Vim & Neovim

**ALE**

[ALE](https://github.com/w0rp/ale) has support for Psalm (since v2.3.0).

```vim
let g:ale_linters = { 'php': ['php', 'psalm'] }
```

**vim-lsp**

I also got it working with [vim-lsp](https://github.com/prabirshrestha/vim-lsp)

This is the config I used (for Vim):

```vim
au User lsp_setup call lsp#register_server({
     \ 'name': 'psalm-language-server',
     \ 'cmd': {server_info->[expand('vendor/bin/psalm-language-server')]},
     \ 'allowlist': ['php'],
     \ })
```

**coc.nvim**

It also works with [coc.nvim](https://github.com/neoclide/coc.nvim).

Add settings to `coc-settings.json`:

```jsonc
  "languageserver": {
    "psalmls": {
      "command": "vendor/bin/psalm-language-server",
      "filetypes": ["php"],
      "rootPatterns": ["psalm.xml", "psalm.xml.dist"],
      "requireRootPattern": true
    }
  }
```

### VS Code

[Get the Psalm plugin here](https://marketplace.visualstudio.com/items?itemName=getpsalm.psalm-vscode-plugin) (Requires VS Code 1.26+):

## Running the server in a docker container

Make sure you use `--map-folder` option. Using it without argument will map the server's CWD to the host's project root folder. You can also specify a custom mapping. For example:
```bash
docker-compose exec php /usr/share/php/psalm/psalm-language-server \
   -r=/var/www/html \
   --map-folder=/var/www/html:$PWD
```

---

### Security Analysis Annotations (`docs/security_analysis/annotations.md`)

# Security analysis annotations

## `@psalm-taint-source <taint-type>`

See [Custom taint sources](custom_taint_sources.md#taint-source-annotation).

## `@psalm-taint-sink <taint-type> <param-name>`

See [Custom taint sinks](custom_taint_sinks.md).

## `@psalm-taint-escape <taint-type #conditional>`

See [Escaping tainted output](avoiding_false_positives.md#escaping-tainted-output).

## `@psalm-taint-unescape <taint-type>`

See [Unescaping statements](avoiding_false_negatives.md#unescaping-statements).

## Taint type complements

Wherever these annotations take a `<taint-type>`, `~(<taint-type>|<taint-type>)` (or `~<taint-type>` for one) stands
for every taint but the ones listed: the built-in ones (`user_secret` and `system_secret` too), the custom ones,
including those other annotations only register later. The ones listed may be aliases, like `input`. Write it without
spaces.

```php
<?php // --taint-analysis

/**
 * Taken from the request line, which can't hold a line break: any input but a header injection
 *
 * @psalm-taint-source ~(header|user_secret|system_secret)
 */
function getRequestPath(): string {}
```

The taints the native types of a value can't hold are still removed from it: a `string` returned by
`getRequestPath()` above can't be a NoSQL query.

## `@psalm-taint-specialize`

See [Specializing taints in functions](avoiding_false_positives.md#specializing-taints-in-functions) and [Specializing taints in classes](avoiding_false_positives.md#specializing-taints-in-classes).

## `@psalm-flow [proxy <function-like>] ( <arg>, [ <arg>, ] ) [ -> return ]`

See [Taint Flow](taint_flow.md#optimized-taint-flow).

Each `<arg>` is a parameter, like `$value`. With `-> return`, an `<arg>` can also be:

- `$this`: the object the method is called on
- a parameter followed by `()`, like `$compute()`: what the callables passed to that parameter return

## `@psalm-flow ( <arg>, [ <arg>, ] ) -> <Class>::$<store>[<key>]` and `@psalm-flow <Class>::$<store>[<key>] -> return`

See [Keyed stores](taint_flow.md#keyed-stores)

---

### Security Analysis Avoiding False Negatives (`docs/security_analysis/avoiding_false_negatives.md`)

# Avoiding false-negatives

## Unescaping statements

Post-processing previously escaped/encoded statements can cause insecure scenarios.
`@psalm-taint-unescape <taint-type>` allows to declare those components insecure explicitly.

```php
<?php

/**
 * @psalm-taint-unescape html
 */
function decode(string $str): string
{
    return str_replace(
        ['&lt;', '&gt;', '&quot;', '&apos;'],
        ['<', '>', '"', '"'],
        $str
    );
}

$safe = htmlspecialchars($_GET['text']);
echo decode($safe);
```

---

### Security Analysis Avoiding False Positives (`docs/security_analysis/avoiding_false_positives.md`)

# Avoiding false-positives

When you run Psalm's taint analysis for the first time you may see a bunch of false-positives.

Nobody likes false-positives!

There are a number of ways you can prevent them:

## Escaping tainted input

Some operations remove taints from data – for example, wrapping `$_GET['name']` in an `htmlentities` call prevents cross-site-scripting attacks in that `$_GET` call.

Psalm allows you to remove taints via a `@psalm-taint-escape <taint-type>` annotation:

```php
<?php

function echoVar(string $str) : void {
    /**
     * @psalm-taint-escape html
     */
    $str = str_replace(['<', '>'], '', $str);
    echo $str;
}

echoVar($_GET["text"]);
```

## Types

A value can only carry the taints its type can hold: a number or a boolean can't hold HTML, SQL or a path, a string can't be a NoSQL query document (but what `json_decode()`, `unserialize()`, `parse_str()` and the other decoders build out of it can), and a literal string (a value the code wrote, or one Psalm knows is among such values) can't hold anything the client sent. An array holds what its keys and values can: `list<int>` holds no HTML, while the string keys of `array<string, int>` can hold anything. A union holds what any of its types can hold, and `null` holds nothing.

Psalm removes the taints a value can't carry where it is cast, passed to a function, returned, or assigned to a variable or a property, using the type it infers for the value, and where PHP guarantees a type:

- casts: `(int) $_GET['id']` is only left with the taints a number can carry;
- the native type of a parameter, inside the function;
- the native return type of a function or method, for what it returns, taint sources included: a method annotated `@psalm-taint-source input` with a `string` return type never returns a NoSQL query.

```php
<?php

/** @psalm-taint-source input */
function getParam(string $name): string {
    return (string) ($_GET[$name] ?? '');
}

function getId(string $name): int {
    return (int) getParam($name);
}

$collection->find(['name' => getParam('name')]); // a string can't inject query operators
echo '<b>' . getId('id') . '</b>'; // an int can't carry HTML

$direction = getParam('direction');
if ($direction === 'asc' || $direction === 'desc') {
    echo $direction; // 'asc'|'desc' is a literal
}
```

A function that validates a value against data the code trusts can tell Psalm about it with `@psalm-assert-if-true literal-string`: once validated, the value can't hold anything the client chose.

```php
<?php

/** @psalm-assert-if-true literal-string $city */
function isKnownCity(string $city): bool {
    return in_array($city, getCityKeysFromDatabase(), true);
}

$city = getParam('city');
if (isKnownCity($city)) {
    $organization->city = $city; // stored without any taint
}
```

## Conditionally escaping tainted input

A slightly modified version of the previous example is using a condition to determine whether the return value
is considered secure. Only in case function argument `$escape` is true, the corresponding annotation
`@psalm-taint-escape` is applied for taint types `html` and `has_quotes`.

```php
<?php
/**
 * @param string $str
 * @param bool $escape
 * @psalm-taint-escape ($escape is true ? 'html'|'has_quotes' : null)
 */
function processVar(string $str, bool $escape = true) : string {
    if ($escape) {
      $str = htmlspecialchars($str, ENT_QUOTES);
    }
    return $str;
}

echo processVar($_GET['text'], false); // detects tainted HTML
echo processVar($_GET['text'], true); // considered secure
```

## Sanitizing HTML user input

Whenever possible, applications should be designed to accept & store user input as discrete text fields, rather than blocks of HTML.  This allows user input to be fully escaped via `htmlspecialchars` or `htmlentities`.  In cases where HTML user input is required (e.g. rich text editors like [TinyMCE](https://www.tiny.cloud/)), a library designed specifically to filter out risky HTML is highly recommended.  For example, [HTML Purifier](http://htmlpurifier.org/docs) could be used as follows:

```php
<?php

/**
 * @psalm-taint-escape html
 * @psalm-taint-escape has_quotes
 */
function sanitizeHTML($html){
    $purifier = new HTMLPurifier();
    return $purifier->purify($html);
}
```

## Specializing taints in functions

For functions, methods and classes you can use the `@psalm-taint-specialize` annotation.

```php
<?php

function takesInput(string $s) : string {
    error_log("Got input");
    return $s;
}

echo htmlentities(takesInput($_GET["name"]));
echo takesInput("hello"); // Psalm detects tainted HTML here
```

Adding a `@psalm-taint-specialize` annotation solves the problem, by telling Psalm that each invocation of the function should be treated separately.

```php
<?php

/**
 * @psalm-taint-specialize
 */
function takesInput(string $s) : string {
    error_log("Got input");
    return $s;
}

echo htmlentities(takesInput($_GET["name"]));
echo takesInput("hello"); // No error
```

A specialized function or method will still track tainted input:

```php
<?php

/**
 * @psalm-taint-specialize
 */
function takesInput(string $s) : string {
    return $s;
}

echo takesInput($_GET["name"]); // Psalm detects tainted input
echo takesInput("hello"); // No error
```

Here we’re telling Psalm that a function’s taintedness is wholly dependent on the input to the function.

If you're familiar with [immutability in Psalm](https://psalm.dev/articles/immutability-and-beyond) then this general idea should be familiar, since a pure function is one where the output is wholly dependent on its input. Unsurprisingly, all functions marked `@psalm-pure` _also_ specialize the taintedness of their output based on input:

```php
<?php

/**
 * @psalm-pure
 */
function takesInput(string $s) : string {
    return $s;
}

echo htmlentities(takesInput($_GET["name"]));
echo takesInput("hello"); // No error
```

Since each invocation is treated separately, a sink the input reaches through a specialized function – in its body or in a function it calls – is reported for every call that passes tainted input to it:

```php
<?php

/**
 * @psalm-taint-specialize
 */
function run(string $command) : void {
    exec($command); // Reported twice: once for each call below
}

run($_GET["first"]);
run($_GET["second"]);
```

Psalm also infers the purity of functions without a purity annotation, so an unannotated function is specialized too when it turns out to be pure, as would be the first `takesInput` above without the `error_log` call. Since a method could be overridden by an impure one, this only applies to methods that cannot be overridden: `private` or `final` methods, and methods of `final` classes.

## Specializing taints in classes

Just as taints can be specialized in function calls, tainted properties can also be specialized to a given class.

```php
<?php

class User {
    public string $name;

    public function __construct(string $name) {
        $this->name = $name;
    }
}

/**
 * @psalm-taint-specialize
 */
function echoUserName(User $user) {
    echo $user->name; // Error, detected tainted input
}

$user1 = new User("Keith");
$user2 = new User($_GET["name"]);

echoUserName($user1);
```

Adding `@psalm-taint-specialize` to the class fixes the issue.

```php
<?php

/**
 * @psalm-taint-specialize
 */
class User {
    public string $name;

    public function __construct(string $name) {
        $this->name = $name;
    }
}

/**
 * @psalm-taint-specialize
 */
function echoUserName(User $user) {
    echo $user->name; // No error
}

$user1 = new User("Keith");
$user2 = new User($_GET["name"]);

echoUserName($user1);
```

Each instance then holds its own taints, which only follow the variables the instance is assigned to. So Psalm makes sure the instance doesn't change once constructed, as the change wouldn't reach the other variables holding the same instance: its properties are readonly, and its methods can't write them. Nor can its methods write other objects, static properties or global variables, from which another instance could read back what this one wrote. To get a changed instance, create a new one, for instance by cloning it:

```php
<?php

/**
 * @psalm-taint-specialize
 */
class User {
    public function __construct(public string $name) {}

    public function withName(string $name): static {
        $new = clone $this;
        $new->name = $name;
        return $new;
    }
}
```

The classes that extend a class with `@psalm-taint-specialize` are specialized too, and held to the same rules: Psalm reports an [ImmutableDependency](../running_psalm/issues/ImmutableDependency.md) issue for those that don't have the annotation themselves.

And, because it’s form of purity enforcement, `@psalm-immutable` can also be used:

```php
<?php

/**
 * @psalm-immutable
 */
class User {
    public string $name;

    public function __construct(string $name) {
        $this->name = $name;
    }
}

/**
 * @psalm-taint-specialize
 */
function echoUserName(User $user) {
    echo $user->name; // No error
}

$user1 = new User("Keith");
$user2 = new User($_GET["name"]);

echoUserName($user1);
```

## Avoiding files in taint paths

You can also tell Psalm that you’re not interested in any taint paths that flow through certain files or directories by specifying them in your Psalm config:

```xml
    <taintAnalysis>
        <ignoreFiles>
            <directory name="tests"/>
        </ignoreFiles>
    </taintAnalysis>
```

---

### Security Analysis Custom Taint Sinks (`docs/security_analysis/custom_taint_sinks.md`)

# Custom Taint Sinks

The `@psalm-taint-sink <taint-type> <param-name>` annotation allows you to define a taint sink.

Any tainted value matching the given [taint type](index.md#taint-types) will be reported as an error by Psalm.

### Example

Here the `PDOWrapper` class has an `exec` method that should not receive tainted SQL, so we can prevent its insertion:

```php
<?php

class PDOWrapper {
    /**
     * @psalm-taint-sink sql $sql
     */
    public function exec(string $sql) : void {}
}
```

### Values of an array

Append `[*]` to the parameter name to make only the values of the array given to the parameter a sink, not its keys:

```php
<?php

final class TemplateLoader {
    /**
     * @param array<string, string> $templates template names => template sources
     * @psalm-taint-sink eval $templates[*]
     */
    public function __construct(private array $templates) {}
}
```

Here a tainted template name is not reported, a tainted template source is.

---

### Security Analysis Custom Taint Sources (`docs/security_analysis/custom_taint_sources.md`)

# Custom Taint Sources

You can define your own taint sources with an annotation or a plugin.

## Taint source annotation

You can use the annotation `@psalm-taint-source <taint-type>` to indicate a function or method that provides user input.

In the below example the `input` taint type is specified as a standin for input taints as defined in [Psalm\Type\TaintKind](https://github.com/vimeo/psalm/blob/master/src/Psalm/Type/TaintKind.php).

```php
<?php
/**
 * @psalm-taint-source input
 */
function getQueryParam(string $name) : string {}
```

## Custom taints declared in the configuration

Custom taints can be declared in `psalm.xml`, so that the annotations can name them without a plugin registering
them:

```xml
<taintAnalysis>
  <taints>
    <taint name="file_upload">
      <alias name="input" />
    </taint>
    <taint name="session_id" />
  </taints>
</taintAnalysis>
```

A taint added to the alias `input` with `<alias name="input" />` is a kind of user input like the built-in ones:
`$_GET` and the other built-in sources of user input give it, `@psalm-taint-source input`, `@psalm-taint-sink input`
and `@psalm-taint-escape input` name it, and a value of a type that can't hold user input (a literal string, a number,
a boolean, null) can't carry it. Plugins get these taints with `Codebase::getInputTaints()`. Each of the other aliases,
`tainted` and `input_except_sleep`, holds the custom taints added to it with its own `<alias>`, and only those. A
taint without an alias, like `session_id` above, only comes from the annotations naming it
(`@psalm-taint-source session_id`), and only reaches the sinks naming it.

A taint's name is a word (letters, digits, `_` and `-`) other than those of the built-in taints.

## Custom taint plugin

For example this plugin treats all variables named `$bad_data` as taint sources.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Security Analysis Taint Flow (`docs/security_analysis/taint_flow.md`)

# Taint Flow

## Optimized Taint Flow

When dealing with frameworks, keeping track of the data flow might involve different layers
and even other 3rd party components. Using the `@psalm-flow` annotation allows PsalmPHP to
take a shortcut and to make a tainted data flow more explicit.

### Proxy hint

```php
<?php // --taint-analysis
/**
 * @psalm-flow proxy exec($value)
 */
function process(string $value): void {}

process($_GET['malicious'] ?? '');
```

The example above states, that the function `process($value)` is a proxy of the native PHP
function `exec($value)` - which is potentially vulnerable to code execution (`TaintedShell`).

**Examples**

+ `@psalm-flow proxy exec($value)` referencing the global/scoped function `exec`
+ `@psalm-flow proxy MyClass::mySinkMethod($value)` referencing a function/method of the class `MyClass`

### Return value hint

```php
<?php // --taint-analysis
/**
 * @psalm-flow ($value, $items) -> return
 */
function inputOutputHandler(string $value, string ...$items): string
{
    // lots of complicated magic
}

echo inputOutputHandler('first', 'second', $_GET['malicious'] ?? '');
```

The example above states, that the function parameters `$value` and `$items` are reflected
again in the return value. Thus, in case any of the input parameters to the function
`inputOutputHandler` is tainted, then the resulting return value is as well. In this
example `TaintedHtml` would be detected due to using `echo`.

### Object to return value hint

```php
<?php // --taint-analysis
interface Message
{
    /**
     * @psalm-taint-specialize
     * @psalm-flow ($this) -> return
     */
    public function getBody(): string;
}

/**
 * @psalm-taint-source input
 */
function fetch(): Message {
    // a request to another server
}

echo fetch()->getBody();
```

`$this` in a return value hint states that what a method returns holds what the object it is called on holds: here,
the bodies of the messages `fetch()` returns are tainted, while those of the messages the code builds itself only hold
what they were given. This is useful for methods whose bodies Psalm doesn't analyze, such as those of interfaces,
stubs and vendor code. With `@psalm-taint-specialize`, each call returns what its own object holds; without it, what
any object the method is called on holds flows into what every call returns.

### Callable result to return value hint

```php
<?php // --taint-analysis
interface Cache
{
    /**
     * @template T
     * @param callable(): T $compute
     * @return T
     * @psalm-taint-specialize
     * @psalm-flow ($compute()) -> return
     */
    public function get(string $key, callable $compute): mixed;
}

function show(Cache $cache): void
{
    echo $cache->get('key', fn(): string => $_GET['malicious'] ?? '');
}
```

`$compute()` in a return value hint states that what the function returns holds what the callables given to `$compute`
return: the closure's body, or the function named. Here `TaintedHtml` is detected. As for `$this`, each call returns
what its own callables return only with `@psalm-taint-specialize`.

### Keyed stores

Caches, key-value stores and similar services keep what they are given out of the analyzed code, under a key. Their
methods can say so, and what is stored under a key then flows into what the reads of that key return, wherever the
code reading it is:

```php
<?php // --taint-analysis
final class Cache
{
    /**
     * @psalm-flow ($value) -> Cache::$data[$key]
     */
    public static function set(string $key, string $value): void {}

    /**
     * @psalm-flow Cache::$data[$key] -> return
     */
    public static function get(string $key): string {}
}

function remember(string $id): void {
    Cache::set('comment_' . $id, $_GET['comment'] ?? '');
}

echo Cache::get('comment_1'); // TaintedHtml
echo Cache::get('title_1');   // no issue
```

+ `($value, $other) -> Store::$data[$key]` stores the arguments given to `$value` and `$other` under the key given to
  `$key`, and `Store::$data[$key] -> return` makes a call return what is stored under its key. `($compute())` stores
  what the callables given to `$compute` return, as in a [return value hint](#callable-result-to-return-value-hint):
  `($compute()) -> Cache::$data[$key]` for a cache computing what it stores when the key is missing.
+ A store is named like a static property, `Class::$name`. The class and the property need not exist; `self` and
  `static` name the class declaring the method. The methods of other classes (a wrapper, an extension) share a store
  by naming the same one.
+ `[*]` is any key: `($values) -> Store::$data[*]` for a method storing an array of keys and values, and
  `Store::$data[*] -> return` for one returning what is stored under any key. `[$keys[*]]` is each key of a list, as
  for `mGet(array $keys)`. In nested stores, like `Store::$data[$namespace][$key]`, only the first key tells the values
  apart.
+ Keys are told apart by what the analysis knows of them: the exact keys of literal strings and class names, else how
  the key starts: the start of a concatenation, of an interpolated string, of a `sprintf()` format up to its first
  conversion other than `%s`, of an `implode()` of a list with a literal separator, `__CLASS__`, or what the variable
  (also one a closure uses), the property of `$this`, the method of the class or the function giving the key starts
  with. A property set only by its default and its constructor starts like what the constructor is given by the `new`
  of the classes analyzed. The keys of a list start like all its items: those of a literal list, those assigned to it
  (`$keys[] = 'lock_' . $id;`), and those of a list a method or a function builds this way and returns. A key the
  analysis knows nothing of can be any key.
+ Psalm's stubs declare the keyed store of phpredis, `Redis::$data`, and that of APCu, `APCu::$data`. Plugins can
  connect their own nodes to a store with `Codebase::addTaintStoreWrite()` (paths from a node into the store under
  the names) and `Codebase::addTaintStoreRead()` (paths from the store to a node), with the names
  `Codebase::getTaintStoreNames()` tells for an expression, for stores whose keys an annotation can't express (a
  table named in an SQL query).

### Combined proxy & return value hint

```php
<?php // --taint-analysis
/**
 * @psalm-flow proxy exec($value)
 * @psalm-flow ($value, $items) -> return
 */
function handleInput(string $value, string ...$items): string
{
    // lots of complicated magic
}

echo handleInput($_GET['malicious'] ?? '');
```

The example above combines both previous examples and shows, that the `@psalm-flow` annotation
can be used multiple times. Here, it would lead to detecting both `TaintedHtml` and `TaintedShell`.

---

### Annotating Code Type Syntax Array Types (`docs/annotating_code/type_syntax/array_types.md`)

# Array types

In PHP, the `array` type is commonly used to represent three different data structures:

[List](https://en.wikipedia.org/wiki/List_(abstract_data_type)):

```php
<?php
$a = [1, 2, 3, 4, 5];
```

[Associative array](https://en.wikipedia.org/wiki/Associative_array):  

```php
<?php
$a = [0 => 'hello', 5 => 'goodbye'];
$b = ['a' => 'AA', 'b' => 'BB', 'c' => 'CC'];
```

Makeshift [Structs](https://en.wikipedia.org/wiki/Struct_(C_programming_language)):

```php
<?php
$a = ['name' => 'Psalm', 'type' => 'tool'];
```

PHP treats all these arrays the same, essentially (though there are some optimisations under the hood for the first case).

Psalm has a few different ways to represent arrays in its type system:

## Generic arrays

Psalm uses a syntax [borrowed from Java](https://en.wikipedia.org/wiki/Generics_in_Java) that allows you to denote the types of both keys *and* values:

```php
/** @return array<TKey, TValue> */
```

You can also specify that an array is non-empty with the special type `non-empty-array<TKey, TValue>`.

### PHPDoc syntax

PHPDoc [allows you to specify](https://docs.phpdoc.org/guide/guides/types.html#arrays) the type of values a generic array holds with the annotation:

```php
/** @return ValueType[] */
```

In Psalm this annotation is equivalent to `@psalm-return array<array-key, ValueType>`.

Generic arrays encompass both _associative arrays_ and _lists_.

## Lists

(Psalm 3.6+)

Psalm supports a `list` type that represents continuous, integer-indexed arrays like `["red", "yellow", "blue"]`.

A frequent way to create a list is with the `$arr[] =` notation.

These arrays will return true to `array_is_list($arr)`(PHP 8.1+) and represent a large percentage of all array usage in PHP applications.

A `list` type is of the form `list<SomeType>`,  where `SomeType` is any permitted [union type](union_types.md) supported by Psalm.

- `list` is a subtype of `array<int, mixed>`
- `list<Foo>` is a subtype of `array<int, Foo>`.

List types show their value in a few ways:

```php
<?php
/**
 * @param array<int, string> $arr
 */
function takesArray(array $arr) : void {
  if ($arr) {
     // this index may not be set
    echo $arr[0];
  }
}

/**
 * @psalm-param list<string> $arr
 */
function takesList(array $arr) : void {
  if ($arr) {
    // list indexes always start from zero,
    // so a non-empty list will have an element here
    echo $arr[0];
  }
}

takesArray(["hello"]); // this is fine
takesArray([1 => "hello"]); // would trigger bug, without warning

takesList(["hello"]); // this is fine
takesList([1 => "hello"]); // triggers warning in Psalm
```

## Array shapes

Psalm supports a special format for arrays where the key offsets are known: array shapes, also known as "object-like arrays".

Given an array

```php
<?php
["hello", "world", "foo" => new stdClass, 28 => false];
```

Psalm will type it internally as:

```
array{0: string, 1: string, foo: stdClass, 28: false}
```

You can specify types in that format yourself, e.g.

```php
/** @return array{foo: string, bar: int} */
```

Optional keys can be denoted by a trailing `?`, e.g.:

```php
/** @return array{optional?: string, bar: int} */
```

You can use "one-line" comments (similar to PHP), e.g:

```php
/** @return array { // Array with comments.
 *     // Comments can be placed on their own line. 
 *     foo: string, // An array key description.
 *     bar: array {, // Another array key description.
 *         'foo//bar': string, // Array key with "//" in it's name.
 *     },
 * }
 */
```

Tip: if you find yourself copying the same complex array shape over and over again to avoid `InvalidArgument` issues, try using [type aliases](utility_types.md#type-aliases), instead.

### Validating array shapes

Use [Valinor](https://github.com/CuyZ/Valinor) in strict mode to easily assert array shapes at runtime using Psalm array shape syntax (instead of manually asserting keys with isset):

```php
try {
  $array = (new \CuyZ\Valinor\MapperBuilder())
      ->mapper()
      ->map(
          'array{a: string, b: int}',
          json_decode(file_get_contents('https://.../'), true)
      );

  /** @psalm-trace $array */; // array{a: string, b: int}

  echo $array['a'];
  echo $array['b'];
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
  // Do something…
}
```

Valinor provides both runtime and static Psalm assertions with full Psalm syntax support and many other features, check out the [Valinor documentation](https://valinor.cuyz.io/latest/) for more info!

## List shapes

Starting in Psalm 5, Psalm also supports a special format for list arrays where the key offsets are known.

Given a list array

```php
<?php
["hello", "world", new stdClass, false];
```

Psalm will type it internally as:

```
list{string, string, stdClass, false}
```

You can specify types in that format yourself, e.g.

```php
/** @return list{string, int} */
/** @return list{0: string, 1: int} */
```

Optional keys can be denoted by a specifying keys for all elements and specifying a trailing `?` for optional keys, e.g.:

```php
/** @return list{0: string, 1?: int} */
```

List shapes are essentially n-tuples [from a type theory perspective](https://en.wikipedia.org/wiki/Tuple#Type_theory).

## Unsealed array and list shapes

Starting from Psalm v5, array shapes and list shapes can be marked as open by adding `...` as their last element.

Here we have a function `handleOptions` that takes an array of options. The type tells us it has a single known key with type `string`, and potentially many other keys of unknown types.

```php
/** @param array{verbose: string, ...} $options */
function handleOptions(array $options): float {
    if ($options['verbose']) {
        var_dump($options);
    }
}

$options = get_opt(/* some code */);
$options['verbose'] = isset($options['verbose']);
handleOptions($options);
```

`...` is a shorthand for `...<array-key, mixed>` you can use other array generic types to provide more information about the open shape.

```php
// This is an open array
/** @param array{someKey: string, ...} */ 
// Which is the same as
/** @param array{someKey: string, ...<array-key, mixed>} */ 
// But it can be further locked down with a shape ...<TKey, TValue>
/** @return array{someKey: string, ...<int, bool>} */
```

## Callable arrays

An array holding a callable, like PHP's native `call_user_func()` and friends supports it:

```php
<?php

$callable = ['myClass', 'aMethod'];
$callable = [$object, 'aMethod'];
```

## non-empty-array

An array which is not allowed to be empty.
[Generic syntax](#generic-arrays) is also supported: `non-empty-array<string, int>`.

---

### Annotating Code Type Syntax Atomic Types (`docs/annotating_code/type_syntax/atomic_types.md`)

# Atomic types

Atomic types are the basic building block of all type information used in Psalm. Multiple atomic types can be combined, either with [union types](union_types.md) or [intersection types](intersection_types.md). Psalm allows many different sorts of atomic types to be expressed in docblock syntax:

**Note**: you can view detailed documentation and usage examples for all atomic types by clicking on each type in the following list.

* [Scalar types](scalar_types.md)
    * [bool](scalar_types.md#scalar)
    * [int](scalar_types.md#scalar)
    * [float](scalar_types.md#scalar)
    * [string](scalar_types.md#scalar)
    * [`int-range<x, y>`](scalar_types.md#int-range)
    * [`int-mask<1, 2, 4>`](scalar_types.md#int-mask1-2-4)
    * [`int-mask-of<MyClass::CLASS_CONSTANT_*>`](scalar_types.md#int-mask-ofmyclassclass_constant_)
    * [class-string and class-string&lt;Foo&gt;](scalar_types.md#class-string-interface-string)
    * [trait-string](scalar_types.md#trait-string)
    * [enum-string](scalar_types.md#enum-string)
    * [callable-string](scalar_types.md#callable-string)
    * [numeric-string](scalar_types.md#numeric-string)
    * [literal-string](scalar_types.md#literal-string)
    * [literal-int](scalar_types.md#literal-int)
    * [array-key](scalar_types.md#array-key)
    * [numeric](scalar_types.md#numeric)
    * [scalar](scalar_types.md#scalar)
* [Object types](object_types.md)
    * [object](object_types.md#unnamed-objects)
    * [object{foo: string}](object_types.md#object-properties)
    * [Exception, Foo\MyClass and `Foo\MyClass<Bar>`](object_types.md#named-objectsmd)
    * [Generator](object_types.md#generators)
* [Array types](array_types.md)
    * [array&lt;int, string&gt;](array_types.md#generic-arrays)
    * [non-empty-array](array_types.md#non-empty-array)
    * [string\[\]](array_types.md#phpdoc-syntax)
    * [list & non-empty-list](array_types.md#lists)
    * [list&lt;string&gt;](array_types.md#lists)
    * [array{foo: int, bar: string} and list{int, string}](array_types.md#object-like-arrays)
    * [callable-array](array_types.md#callable-arrays)
* [Callable types](callable_types.md)
* [Value types](value_types.md)
    * [null](value_types.md#null)
    * [true, false](value_types.md#true-false)
    * [6, 7.0, "forty-two" and 'forty two'](value_types.md#some_string-4-314)
    * [Foo\Bar::MY_SCALAR_CONST](value_types.md#regular-class-constants)
* [Utility types](utility_types.md)
    * [(T is true ? string : bool)](conditional_types.md)
    * [`key-of<T>`](utility_types.md#key-oft)
    * [`value-of<T>`](utility_types.md#value-oft)
    * [`properties-of<T>`](utility_types.md#properties-oft)
    * [`class-string-map<T of Foo, T>`](utility_types.md#class-string-mapt-of-foo-t)
    * [`T[K]`](utility_types.md#tk)
    * [Type aliases](utility_types.md#type-aliases)
    * [Variable templates](utility_types.md#variable-templates)
* [Other types](other_types.md)
    * [`iterable<TKey, TValue>`](other_types.md)
    * [void](other_types.md)
    * [resource](other_types.md)
    * [closed-resource](other_types.md)
* [Top and bottom types](top_bottom_types.md)
    * [mixed](top_bottom_types.md#mixed)
    * [never](top_bottom_types.md#never)

---

### Annotating Code Type Syntax Callable Types (`docs/annotating_code/type_syntax/callable_types.md`)

# Callable types

Psalm supports a special format for `callable`s of the form. It can also be used for annotating `Closure`.

```
callable(Type1, OptionalType2=, SpreadType3...):ReturnType
```

Adding `=` after the type implies it is optional, and suffixing with `...` implies the use of the spread operator.

Using this annotation you can specify that a given function return a `Closure` e.g.

```php
<?php
/**
 * @return Closure(bool):int
 */
function delayedAdd(int $x, int $y) : Closure {
  return function(bool $debug) use ($x, $y) {
    if ($debug) echo "got here" . PHP_EOL;
    return $x + $y;
  };
}

$adder = delayedAdd(3, 4);
echo $adder(true);
```

## Pure callables

A callable type carries the capabilities (see [the purity model](../purity_model.md#capabilities))
the callable may use, given in square brackets after the keyword:

* `Closure[pure](int): int` / `callable[pure](int): int` - a pure callable, also written `pure-Closure(int): int` / `pure-callable(int): int`
* `Closure[write-props|io](): void` - any combination of capabilities
* `Closure[P](): void` - a purity template declared with `@psalm-purity-template`
* `Closure[_](): void` - in a parameter's type only, at any depth: the function inherits its purity from that parameter (see [purity templates](../purity_model.md#purity-templates))
* `Closure(): void` / `callable(): void` - an impure callable (the default), also written `impure-Closure(): void` / `impure-callable(): void`

The parameter list may be left out: `Closure[pure]` is any pure closure.

A callable needing fewer capabilities fits where more are allowed: a `pure-Closure` can be passed
for a `Closure[io]` parameter, but not the other way round. A closure's capabilities are inferred
from its body, so its type carries what it actually does.

This can be useful when the `callable` is used in a function with few capabilities (see [`@psalm-capabilities`](../supported_annotations.md#psalm-capabilities)), for example:

```php
<?php
/** @psalm-immutable */
class intList {
    /** @param list<int> $items */
    public function __construct(private array $items) {}
    
    /**
     * @param pure-callable(int, int): int $callback
     * @psalm-capabilities read-props
     */
    public function walk(callable $callback): int {
        return array_reduce($this->items, $callback, 0);
    }
}

$list = new intList([1,2,3]);

// This is ok, as the callable is pure
echo $list->walk(fn (int $c, int $v): int => $c + $v);

// This will cause an InvalidArgument error, as the closure calls an impure function
echo $list->walk(fn (int $c, int $v): int => $c + random_int(1, $v));
```

---

### Annotating Code Type Syntax Conditional Types (`docs/annotating_code/type_syntax/conditional_types.md`)

# Conditional types

Psalm supports the equivalent of TypeScript’s [conditional types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types).

Conditional types have the form:

`(<template param> is <union type> ? <union type> : <union type>)`

All conditional types must be wrapped inside brackets e.g. `(...)`

Conditional types are dependent on [template parameters](../templated_annotations.md), so you can only use them in a function where template parameters are defined.

## Example application

Let's suppose we want to make a userland implementation of PHP's numeric addition (but please never do this). You could type this with a conditional return type:

```php
<?php

/**
 * @template T of int|float
 * @param T $a
 * @param T $b
 * @return int|float
 * @psalm-return (T is int ? int : float)
 */
function add($a, $b) {
    return $a + $b;
}
```

When figuring out the result of `add($x, $y)` Psalm tries to infer the value `T` for that particular call. When calling `add(1, 2)`, `T` can be trivially inferred as an `int`. Then Psalm takes the provided conditional return type

`(T is int ? int : float)`

and substitutes in the known value of `T`, `int`, so that expression becomes

`(int is int ? int : float)`

which simplifies to `(true ? int : float)`, which simplifies to `int`.

Calling `add(1, 2.1)` means `T` would instead be inferred as `int|float`, which means the expression `(T is int ? int : float)` would instead have the substitution

`(int|float is int ? int : float)`

The union `int|float` is clearly not an `int`, so the expression is simplified to `(false ? int : float)`, which simplifies to `float`.

## Nested conditionals

You can also nest conditionals just as you could ternary expressions:

```php
<?php

class A {
    const TYPE_STRING = 0;
    const TYPE_INT = 1;

    /**
     * @template T of int
     * @param T $i
     * @psalm-return (
     *     T is self::TYPE_STRING
     *     ? string
     *     : (T is self::TYPE_INT ? int : bool)
     * )
     */
    public static function getDifferentType(int $i) {
        if ($i === self::TYPE_STRING) {
            return "hello";
        }

        if ($i === self::TYPE_INT) {
            return 5;
        }

        return true;
    }
}


```

---

### Annotating Code Type Syntax Intersection Types (`docs/annotating_code/type_syntax/intersection_types.md`)

# Intersection types

An annotation of the form `Type1&Type2&Type3` is an _Intersection Type_. Any value must satisfy `Type1`, `Type2` and `Type3` simultaneously. `Type1`, `Type2` and `Type3` are all [atomic types](atomic_types.md).

For example, after this statement in a PHPUnit test:

```php
<?php

$hare = $this->createMock(Hare::class);
```

`$hare` will be an instance of a class that extends `Hare`, and implements `\PHPUnit\Framework\MockObject\MockObject`. So
`$hare` is typed as `Hare&\PHPUnit\Framework\MockObject\MockObject`. You can use this syntax whenever a value is
required to implement multiple interfaces.

Another use case is being able to merge object-like arrays:

```php
/**
 * @psalm-type A=array{a: int}
 * @psalm-type B=array{b: int}
 *
 * @param A $a
 * @param B $b
 *
 * @return A&B
 */
function foo($a, $b) {
    return $a + $b;
}
```

The returned type will contain the properties of both `A` and `B`. In other words, it will be `{a: int, b: int}`.

Intersections are only valid for lists of only *object types* and lists of only *object-like arrays*.

You can also intersect a class with an object shape to describe properties the class doesn't declare. This helps with
classes that read properties through the magic `__get` method, where Psalm can't know which properties exist:

```php
<?php

class Row
{
    /** @param array<string, mixed> $columns */
    public function __construct(private array $columns) {}

    public function __get(string $name): mixed
    {
        return $this->columns[$name] ?? null;
    }
}

/** @param Row&object{email: string} $user */
function sendWelcomeEmail(Row $user): void
{
    mail($user->email, 'Welcome!', 'Thanks for signing up.');
}
```

With a plain `Row`, `$user->email` would be `mixed`. With `Row&object{email: string}` it is a `string`.

Psalm takes a property from the shape only when the class doesn't declare it. The shape takes priority over a property
that comes from a `@mixin`. A `final` class can only have undeclared properties through `__get`, so for a final class
without `__get` (its own or inherited) Psalm still reports `UndefinedPropertyFetch`.

---

### Annotating Code Type Syntax Object Types (`docs/annotating_code/type_syntax/object_types.md`)

# Object types

## Unnamed objects

`object` are examples of unnamed object types. This type is also a valid type in PHP.

## Named objects

`stdClass`, `Foo`, `Bar\Baz` etc. are examples of named object types. These types are also valid types in PHP.

## Object properties

Psalm supports specifying the properties of an object and their expected types, e.g.:

```php
/** @param object{foo: string} $obj */
function takesObject(object $obj) : string {
    return $obj->foo;
}

takesObject((object) ["foo" => "hello"]);
```

Optional properties can be denoted by a trailing `?`, e.g.:

```php
/** @param object{optional?: string} */
```

## Generic object types

Psalm supports using generic object types like `ArrayObject<int, string>`. Any generic object should be typehinted with appropriate [`@template` tags](../templated_annotations.md).

## Generators

Generator types support up to four parameters, e.g. `Generator<int, string, mixed, void>`:

1. `TKey`, the type of the `yield` key - default: `mixed`
2. `TValue`, the type of the `yield` value - default: `mixed`
3. `TSend`, the type of the `send()` method's parameter - default: `mixed`
4. `TReturn`, the return type of the `getReturn()` method - default: `mixed`

`Generator<int>` is a shorthand for `Generator<mixed, int, mixed, mixed>`.

`Generator<int, string>` is a shorthand for `Generator<int, string, mixed, mixed>`.

---

### Annotating Code Type Syntax Other Types (`docs/annotating_code/type_syntax/other_types.md`)

# Other types

- `iterable` - represents the [iterable pseudo-type](https://php.net/manual/en/language.types.iterable.php). Like arrays, iterables can have type parameters e.g. `iterable<string, Foo>`, and a purity in brackets, what iterating over them may do: `iterable[pure]<string, Foo>` accepts arrays and `Traversable[pure]<string, Foo>` (see [Iterators and generators](../purity_model.md#iterators-and-generators)).
- `void` - can be used in a return type when a function does not return a value.
- `resource` represents a [PHP resource](https://www.php.net/manual/en/language.types.resource.php).
- `closed-resource` represents a [PHP resource](https://www.php.net/manual/en/language.types.resource.php) that was closed (using `fclose` or another closing function).

---

### Annotating Code Type Syntax Scalar Types (`docs/annotating_code/type_syntax/scalar_types.md`)

# Scalar types

## scalar

`int`, `bool`, `float`, `string` are examples of scalar types. Scalar types represent scalar values in PHP. These types are also valid types in PHP 7.
The type `scalar` is the supertype of all scalar types.

## int-range

Integer ranges indicate an integer within a range, specified using generic syntax: `int<x, y>`.  
`x` and `y` must be integer numbers.  
`x` can also be `min` to indicate PHP_INT_MIN, and `y` can be `max` to indicate PHP_INT_MAX.

Examples:

* `int<-1, 3>`
* `int<min, 0>`
* `int<1, max>` (equivalent to `positive-int`)
* `int<0, max>` (equivalent to `non-negative-int`)
* `int<min, -1>` (equivalent to `negative-int`)
* `int<min, 0>` (equivalent to `non-positive-int`)
* `int<min, max>` (equivalent to `int`)

## int-mask&lt;1, 2, 4&gt;

Represents the type that is the result of a bitmask combination of its parameters.  
`int-mask<1, 2, 4>` corresponds to `0|1|2|3|4|5|6|7`.  

## int-mask-of&lt;MyClass::CLASS_CONSTANT_*&gt;

Represents the type that is the result of a bitmask combination of its parameters.  
This is the same concept as [`int-mask`](#int-mask1-2-4) but this type is used with a reference to constants in code: `int-mask-of<MyClass::CLASS_CONSTANT_*>` will correspond to `0|1|2|3|4|5|6|7` if there are three constants called `CLASS_CONSTANT_{A,B,C}` with values 1, 2 and 4.  

### Comparing masks

A value of an `int-mask` or `int-mask-of` type is a set of bits, and Psalm remembers it through `&`, `|` and `^`: `$mask & B` is a narrowed mask of the bits of `B`. A mask may only be compared by value with `0` (no bit set) or with all of its bits: any other comparison only matches one exact set of bits, where testing some bits with `($mask & B) === B` or `($mask & B) !== 0` is usually meant, and is reported as [IntMaskComparison](../../running_psalm/issues/IntMaskComparison.md).  

## array-key

`array-key` is the supertype (but not a union) of `int` and `string`.

## numeric

`numeric` is a supertype of `int` or `float` or [`numeric-string`](#numeric-string).

## class-string, interface-string

Psalm supports a special meta-type for `MyClass::class` constants, `class-string`, which can be used everywhere `string` can.

For example, given a function with a `string` parameter `$class_name`, you can use the annotation `@param class-string $class_name` to tell Psalm make sure that the function is always called with a `::class` constant in that position:

```php
<?php
class A {}

/**
 * @param class-string $s
 */
function takesClassName(string $s) : void {}
```

`takesClassName("A");` would trigger a `TypeCoercion` issue, whereas `takesClassName(A::class)` is fine.

You can also parameterize `class-string` with an object name e.g. [`class-string<Foo>`](value_types.md#regular-class-constants). This tells Psalm that any matching type must either be a class string of `Foo` or one of its descendants.

## trait-string

Psalm also supports a `trait-string` annotation denoting a trait that exists.

## enum-string

Psalm also supports a `enum-string` annotation denote an enum that exists.

## callable-string

`callable-string` denotes a string value that has passed an `is_callable` check.

## numeric-string

`numeric-string` denotes a string value that has passed an `is_numeric` check.

## literal-string

`literal-string` denotes a string value that is entirely composed of strings in your application.

Examples:

- `"hello " . "world"`
- `"hello " . Person::DEFAULT_NAME`
- `implode(', ', ["one", "two"])`
- `implode(', ', [1, 2, 3])`
- `"hello " . <another literal-string>`

Strings that don't pass this type check:

- `file_get_contents("foo.txt")`
- `$_GET["foo"]`
- `"hello " . $_GET["foo"]`

## literal-int

`literal-int` denotes an int value that is entirely composed of literal integers in your application.

Examples:

- `12`
- `12+42`

Integers that don't pass this type check:

- `(int) file_get_contents("foo.txt")`
- `(int) $_GET["foo"]`
- `((int)$_GET["foo"]) + 2`

## lowercase-string, non-empty-string, non-empty-lowercase-string

A non empty string, lowercased or both at once.

`empty` here is defined as all strings except the empty string `''`. Another type `non-falsy-string` is effectively a subtype of `non-empty-string`, and also precludes the string value `'0'`.

---

### Annotating Code Type Syntax Top Bottom Types (`docs/annotating_code/type_syntax/top_bottom_types.md`)

# Top types, bottom types

## `mixed`

This is the _top type_ in PHP's type system, and represents a lack of type information. Psalm warns about `mixed` types when the `reportMixedIssues` flag is turned on, or when you're on level 1.

## `never`

It can be aliased to `no-return` or `never-return` in docblocks. Note: it replaced the old `empty` type that used to exist in Psalm

This is the _bottom type_ in PHP's type system. It's used to describe a type that has no possible value. It can happen in multiple cases:

- the actual `never` type from PHP 8.1 (can be used in docblocks for older versions). This type can be used as a return type for functions that will never return, either because they always throw exceptions or always exit()
- a union type that has been stripped of all its possible types. (For example, if a variable is `string|int` and we perform an is_bool() check in a condition, the type of the variable in the condition will be `never` as the condition will never be entered)
- it can represent a placeholder for types yet to come — a good example is the type of the empty array `[]`, which Psalm types as `array<never, never>`, the content of the array is void so it can accept any content
- it can also happen in the same context as the line above for templates that have yet to be defined

---

### Annotating Code Type Syntax Union Types (`docs/annotating_code/type_syntax/union_types.md`)

# Union Types

An annotation of the form `Type1|Type2|Type3` is a _Union Type_. `Type1`, `Type2` and `Type3` are all acceptable possible types of that union type.

`Type1`, `Type2` and `Type3` are each [atomic types](atomic_types.md).

Union types can be generated in a number of different ways, for example in ternary expressions:

```php
<?php
$rabbit = rand(0, 10) === 4 ? 'rabbit' : ['rabbit'];
```

`$rabbit` will be either a `string` or an `array`. We can represent that idea with Union Types – so `$rabbit` is typed as `string|array`. Union types represent *all* the possible types a given variable can have.

PHP builtin functions also have union-type returns - `strpos` can return `false` in some situations, `int` in others. We represent that union type with `int|false`.

---

### Annotating Code Type Syntax Utility Types (`docs/annotating_code/type_syntax/utility_types.md`)

# Utility types

Psalm supports some _magical_ utility types that brings superpower to the PHP type system.

## key-of&lt;T&gt;

(Psalm 5.0+)

The `key-of` utility returns the offset-type for any [array type](array_types.md).

Some examples:

- `key-of<Foo\Bar::ARRAY_CONST>` evaluates to offset-type of `ARRAY_CONST` (Psalm 3.3+)
- `key-of<list<mixed>>` evaluates to `int`
- `key-of<array{a: mixed, b: mixed}|array{c: mixed}>` evaluates to `'a'|'b'|'c'`
- `key-of<string[]>` evaluates to `array-key`
- `key-of<T>` evaluates to the template param's offset-type (ensure `@template T of array`)

### Notes on template usage

If you use `key-of` with a template param, you can fulfill the type check only with these allowed methods:

- `array_keys($t)`
- `array_key_first($t)`
- `array_key_last($t)`

Currently `array_key_exists($key, $t)` **does not** infer that `$key` is of `key-of<T>`.

```php
/**
 * @template T of array
 * @param T $array
 * @return list<key-of<T>>
 */
function getKeys($array) {
    return array_keys($array);
}
```

## value-of&lt;T&gt;

(Psalm 5.0+)

The `value-of` utility returns the value-type for any [array type](array_types.md).

Some examples:

- `value-of<Foo\Bar::ARRAY_CONST>` evaluates to value-type of `ARRAY_CONST` (Psalm 3.3+)
- `value-of<list<float>>` evaluates to `float`
- `value-of<array{a: bool, b: int}|array{c: string}>` evaluates to `bool|int|string`
- `value-of<string[]>` evaluates to `string`
- `value-of<T>` evaluates to the template param's value-type (ensure `@template T of array`)

### Use with enumerations

In addition to array-types, `value-of` can also be used to specify an `int` or `string` that contains one of the possible values of a `BackedEnum`:

- `value-of<Suit>` evaluates to `'H'|'D'|'C'|'S'` (see [Backed enumerations](https://www.php.net/manual/en/language.enumerations.backed.php))
- `value-of<BinaryDigits>` evaluates to `0|1`

### Notes on template usage

If you use `value-of` with a template param, you can fulfill the type check only with these allowed methods:

- `array_values`

```php
/**
 * @template T of array
 * @param T $array
 * @return value-of<T>[]
 */
function getValues($array) {
    return array_values($array);
}
```

Currently `in_array($value, $t)` **does not** infer that `$value` is of `value-of<T>`.

## properties-of&lt;T&gt;

(Psalm 5.0+)

This collection of _utility types_ construct a keyed-array type, with the names of non-static properties of a class as
keys, and their respective types as values. This can be useful if you need to convert objects into arrays.

```php
class A {
  public string $foo = 'foo!';
  public int $bar = 42;

  /**
   * @return properties-of<self>
   */
  public function asArray(): array {
    return [
      'foo' => $this->foo,
      'bar' => $this->bar,
    ];
  }

  /**
   * @return list<key-of<properties-of<self>>>
   */
  public function attributeNames(): array {
    return ['foo', 'bar']
  }
}
```

### Variants

Note that `properties-of<T>` will return **all non-static** properties. There are the following subtypes to pick only
properties with a certain visibility:

- `public-properties-of<T>`
- `protected-properties-of<T>`
- `private-properties-of<T>`

### Sealed array support

Use final classes if you want to properties-of and get_object_vars to return sealed arrays:

```php
/**
 * @template T
 * @param T $object
 * @return properties-of<T>
 */
function asArray($object): array {
  return get_object_vars($object);
}


class A {
  public string $foo = 'foo!';
  public int $bar = 42;
}

final class B extends A {
  public float $baz = 2.1;
}

$a = asArray(new A);
/** @psalm-trace $a */; // array{foo: string, bar: int, ...}

$b = asArray(new B);
/** @psalm-trace $b */; // array{foo: string, bar: int, baz: float}
```

## class-string-map&lt;T of Foo, T&gt;

Used to indicate an array where each value is equal an instance of the class string contained in the key:

```php
<?php

/**
 * @psalm-consistent-constructor
 */
class Foo {}

/**
 * @psalm-consistent-constructor
 */
class Bar extends Foo {}

class A {
  /** @var class-string-map<T of Foo, T> */
  private static array $map = [];

  /**
   * @template U of Foo
   * @param class-string<U> $class
   * @return U
   */
  public static function get(string $class) : Foo {
    if (isset(self::$map[$class])) {
      return self::$map[$class];
    }

    self::$map[$class] = new $class();
    return self::$map[$class];
  }
}

$foo = A::get(Foo::class);
$bar = A::get(Bar::class);

/** @psalm-trace $foo */; // Foo
/** @psalm-trace $bar */; // Bar
```

If we had used an `array<class-string<Foo>, Foo>` instead of a `class-string-map<T of Foo, T>` in the above example, we would've gotten some false positive `InvalidReturnStatement` issues, caused by the lack of a type assertion inside the `isset`.  
On the other hand, when using `class-string-map`, Psalm assumes that the value obtained by using a key `class-string<T>` is always equal to `T`.  

Unbounded templates can also be used for unrelated classes:

```php
<?php

/**
 * @psalm-consistent-constructor
 */
class Foo {}

/**
 * @psalm-consistent-constructor
 */
class Bar {}

/**
 * @psalm-consistent-constructor
 */
class Baz {}

class A {
  /** @var class-string-map<T, T> */
  private static array $map = [];

  /**
   * @template U
   * @param class-string<U> $class
   * @return U
   */
  public static function get(string $class) : object {
    if (isset(self::$map[$class])) {
      return self::$map[$class];
    }

    self::$map[$class] = new $class();
    return self::$map[$class];
  }
}

$foo = A::get(Foo::class);
$bar = A::get(Bar::class);
$baz = A::get(Baz::class);

/** @psalm-trace $foo */; // Foo
/** @psalm-trace $bar */; // Bar
/** @psalm-trace $baz */; // Baz
```

## `T[K]`

Used to get the value corresponding to the specified key:

```php
<?php

/**
 * @template T of array
 * @template TKey of string
 * @param T $arr
 * @param TKey $k
 * @return T[TKey]
 */
function a(array $arr, string $k): mixed {
  assert(isset($arr[$k]));
  return $arr[$k];
}

$a = a(['test' => 123], 'test');
/** @psalm-trace $a */; // 123
```

## Type aliases

Psalm allows defining type aliases for complex types (like array shapes) which must be reused often:

```php
/**
 * @psalm-type PhoneType = array{phone: string}
 */
class Phone {
    /**
     * @psalm-return PhoneType
     */
    public function toArray(): array {
        return ["phone" => "Nokia"];
    }
}
```

You can use the [`@psalm-import-type`](../supported_annotations.md#psalm-import-type) annotation to import a type defined with [`@psalm-type`](../supported_annotations.md#psalm-type) if it was defined somewhere else.

```php
<?php
/**
 * @psalm-import-type PhoneType from Phone
 */
class User {
    /**
     * @psalm-return PhoneType
     */
    public function toArray(): array {
        return array_merge([], (new Phone())->toArray());
    }
}
```

You can also alias a type when you import it:

```php
<?php
/**
 * @psalm-import-type PhoneType from Phone as MyPhoneTypeAlias
 */
class User {
    /**
     * @psalm-return MyPhoneTypeAlias
     */
    public function toArray(): array {
        return array_merge([], (new Phone())->toArray());
    }
}
```

## Variable templates

Variable templates allow directly using variables instead of template types, for example instead of the following verbose example:

```php
<?php

/**
 * @template TA of string
 * @template TB of string
 * @template TChoose of bool
 * @param TA $a
 * @param TB $b
 * @param TChoose $choose
 * @return (TChoose is true ? TA : TB)
 */
function pick(string $a, string $b, bool $choose): string {
  return $choose ? $a : $b;
}

$a = pick('a', 'b', true);
/** @psalm-trace $a */; // 'a'

$a = pick('a', 'b', false);
/** @psalm-trace $a */; // 'b'
```

We can instead use variable templates like so:

```php
<?php

/**
 * @return ($choose is true ? $a : $b)
 */
function pick(string $a, string $b, bool $choose): string {
  return $choose ? $a : $b;
}

$a = pick('a', 'b', true);
/** @psalm-trace $a */; // 'a'

$a = pick('a', 'b', false);
/** @psalm-trace $a */; // 'b'
```

---

### Annotating Code Type Syntax Value Types (`docs/annotating_code/type_syntax/value_types.md`)

# Value types

Psalm also allows you to specify values in types.

## null

This is the `null` value, destroyer of worlds. Use it sparingly. Psalm supports you writing `?Foo` to mean `null|Foo`.

## true, false

Use of `true` and `false` is also PHPDoc-compatible

## "some_string", 4, 3.14

Psalm also allows you specify literal values in types, e.g. `@return "good"|"bad"`

## Regular class constants

Psalm allows you to include class constants in types, e.g. `@return Foo::GOOD|Foo::BAD`. You can also specify explicit class strings e.g. `Foo::class|Bar::class`

If you want to specify that a parameter should only take class strings that are, or extend, a given class, you can use the annotation `@param class-string<Foo> $foo_class`. If you only want the param to accept that exact class string, you can use the annotation `Foo::class`:

```php
<?php
class A {}
class AChild extends A {}
class B {}
class BChild extends B {}

/**
 * @param class-string<A>|class-string<B> $s
 */
function foo(string $s) : void {}

/**
 * @param A::class|B::class $s
 */
function bar(string $s) : void {}

foo(A::class); // works
foo(AChild::class); // works
foo(B::class); // works
foo(BChild::class); // works
bar(A::class); // works
bar(AChild::class); // fails
bar(B::class); // works
bar(BChild::class); // fails
```

---

### Running Psalm Issues AbstractInstantiation (`docs/running_psalm/issues/AbstractInstantiation.md`)

# AbstractInstantiation

Emitted when an attempt is made to instantiate an abstract class:

```php
<?php

abstract class A {}
new A();
```

---

### Running Psalm Issues AbstractMethodCall (`docs/running_psalm/issues/AbstractMethodCall.md`)

# AbstractMethodCall

Emitted when an attempt is made to call an abstract static method directly

```php
<?php

abstract class Base {
    abstract static function bar() : void;
}

Base::bar();
```

## Why this is bad

It's not allowed by PHP.

---

### Running Psalm Issues AmbiguousConstantInheritance (`docs/running_psalm/issues/AmbiguousConstantInheritance.md`)

# AmbiguousConstantInheritance

Emitted when a constant is inherited from multiple sources.

```php
<?php

interface Foo
{
    /** @var non-empty-string */
    public const CONSTANT='foo';
}

interface Bar
{
    /**
     * @var non-empty-string
     */
    public const CONSTANT='bar';
}

interface Baz extends Foo, Bar {}
```

```php
<?php

interface Foo
{
    /** @var non-empty-string */
    public const CONSTANT='foo';
}

class Bar
{
    /** @var non-empty-string */
    public const CONSTANT='bar';
}

class Baz extends Bar implements Foo {}
```

---

### Running Psalm Issues ArgumentTypeCoercion (`docs/running_psalm/issues/ArgumentTypeCoercion.md`)

# ArgumentTypeCoercion

Emitted when calling a function with an argument which has a less specific type than the function expects

```php
<?php

class A {}
class B extends A {}

function takesA(A $a) : void {
    takesB($a);
}
function takesB(B $b) : void {}
```

## How to fix

You could add a typecheck before the call to `takesB`:

```php
<?php

function takesA(A $a) : void {
    if ($a instanceof B) {
        takesB($a);
    }
}
```

Or, if you have control over the function signature of `takesA` you can change it to expect `B`:

```php
<?php

function takesA(B $a) : void {
    takesB($a);
}
```

---

### Running Psalm Issues AssignmentToVoid (`docs/running_psalm/issues/AssignmentToVoid.md`)

# AssignmentToVoid

Emitted when assigning from a function that returns `void`:

```php
<?php

function foo() : void {}
$a = foo();
```

## Why this is bad

Though `void`-returning functions are treated by PHP as returning `null` (so this on its own does not lead to runtime errors), `void` is a concept more broadly in programming languages which is not designed for assignment purposes.

## How to fix

You should just be able to remove the assignment entirely:

```php
<?php

function foo() : void {}
foo();
```

---

### Running Psalm Issues CheckType (`docs/running_psalm/issues/CheckType.md`)

# CheckType

Checks if a variable matches a specific type.
Similar to [Trace](./Trace.md), but only shows if the type does not match the expected type.

```php
<?php

/** @psalm-check-type $x = 1 */
$x = 2; // Checked variable $x = 1 does not match $x = 2
```


```php
<?php

/** @psalm-check-type-exact $x = int */
$x = 2; // Checked variable $x = int does not match $x = 2
```

---

### Running Psalm Issues CircularReference (`docs/running_psalm/issues/CircularReference.md`)

# CircularReference

Emitted when a class references itself as one of its parents

```php
<?php

class A extends B {}
class B extends A {}
```

## Why this is bad

The code above will not compile

---

### Running Psalm Issues ClassMustBeFinal (`docs/running_psalm/issues/ClassMustBeFinal.md`)

# ClassMustBeFinal

Emitted when a non-final, non-abstract class with no child classes is found.  

```php
<?php

class A {}
```

## Why this is bad

Non-final classes are bad for multiple reasons:

- They allow overriding non-final methods and properties, which can lead to unexpected behavior and bugs if implementation details are changed during inheritance of classes not explicitly part of the public API (marked using the `@api` attribute).  
- A corollary of the above is that non-final classes increase the amount of code that must be covered by any backwards-compatibility promise.  
  - In final classes, only public functions/properties/constants must be covered by the backwards compatibility promise.  
  - In non-final classes, all private, protected and public functions/properties/constants must be covered by the backwards compatibility promise (private methods too, because changes to their code may not be compatible with overridden protected/public methods).
- They are not optimized by Opcache and PHP itself, and thus are more expensive to use at runtime.  
- Psalm type inference is more complex and not as exact for non-`final` classes.  

In general, the number of non-final classes in the codebase should be reduced as much as possible, both to speed up code execution and avoid unexpected bugs.  

## How to fix

Recommended, make the class `final`:    

```php
<?php

final class A {}
```

The above can also be automated using `vendor/bin/psalm --alter --issues=ClassMustBeFinal`.  

If inheritance should still be allowed, reduce the surface covered by the backwards compatibility promise by making the class abstract (containing **only** the logic that should be overridable), and move any non-overridable logic to a new `A` class:

```php
<?php

abstract class A {}

final class NewA extends A {}
```

**Note**: if non-`final` classes are needed for mocking in unit tests, simply use [dg/bypass-finals](https://packagist.org/packages/dg/bypass-finals) in your unit tests to allow mocking `final` classes.  

An alternative, not recommended for the [above reasons](#why-this-is-bad), is to make the class part of the public API of your library with `@api`.

---

### Running Psalm Issues ComplexFunction (`docs/running_psalm/issues/ComplexFunction.md`)

# ComplexFunction

Emitted when a function is too complicated. Complicated functions should be split up.

---

### Running Psalm Issues ComplexMethod (`docs/running_psalm/issues/ComplexMethod.md`)

# ComplexMethod

Emitted when a method is too complicated. Complicated methods should be split up.

---

### Running Psalm Issues ConfigIssue (`docs/running_psalm/issues/ConfigIssue.md`)

# ConfigIssue

Emitted for non-fatal configuration issues, e.g. deprecated configuration switches.

## Why this is bad

Your config file may be incompatible with future Psalm versions.

---

### Running Psalm Issues ConflictingReferenceConstraint (`docs/running_psalm/issues/ConflictingReferenceConstraint.md`)

# ConflictingReferenceConstraint

Emitted when a by-ref variable is set in two different branches of an if to different types.

```php
<?php

 class A {
    /** @var int */
    private $foo;

    public function __construct(int &$foo) {
        $this->foo = &$foo;
    }
}

class B {
    /** @var string */
    private $bar;

    public function __construct(string &$bar) {
        $this->bar = &$bar;
    }
}

if (rand(0, 1)) {
    $v = 5;
    $c = (new A($v)); // $v is constrained to an int
} else {
    $v = "hello";
    $c = (new B($v)); // $v is constrained to a string
}

$v = 8;
```

## Why this is bad

Psalm doesn't understand what the type of `$c` should be

---

### Running Psalm Issues ConstantDeclarationInTrait (`docs/running_psalm/issues/ConstantDeclarationInTrait.md`)

# ConstantDeclarationInTrait

Emitted when a trait declares a constant in PHP <8.2.0

```php
<?php

trait A {
    const B = 0;
}
```

## Why this is bad

A fatal error will be thrown.

---

### Running Psalm Issues ConstructorSignatureMismatch (`docs/running_psalm/issues/ConstructorSignatureMismatch.md`)

# ConstructorSignatureMismatch

Emitted when a constructor parameter differs from a parent constructor parameter, or if there are fewer parameters than the parent constructor AND where the parent class has a `@psalm-consistent-constructor` annotation.

```php
<?php

/**
 * @psalm-consistent-constructor
 */
class A {
    public function __construct(int $s) {}
}
class B extends A {
    public function __construct(string $s) {}
}
```

---

### Running Psalm Issues ContinueOutsideLoop (`docs/running_psalm/issues/ContinueOutsideLoop.md`)

# ContinueOutsideLoop

Emitted when encountering a `continue` statement outside a loop context.

```php
<?php

$a = 5;
continue;
```

## Why this is bad

The code won't compile in PHP 5.6 and above.

---

### Running Psalm Issues DeprecatedClass (`docs/running_psalm/issues/DeprecatedClass.md`)

# DeprecatedClass

Emitted when referring to a deprecated class:

```php
<?php

/** @deprecated */
class A {}
new A();
```

## Why this is bad

The `@deprecated` tag is normally indicative of code that will stop working in the near future.

## How to fix

Don’t use the deprecated class.

---

### Running Psalm Issues DeprecatedConstant (`docs/running_psalm/issues/DeprecatedConstant.md`)

# DeprecatedConstant

Emitted when referring to a deprecated constant or enum case:

```php
<?php

class A {
    /** @deprecated */
    const FOO = 'foo';
}

echo A::FOO;

enum B {
    /** @deprecated */
    case B;
}

echo B::B;
```

## Why this is bad

The `@deprecated` tag is normally indicative of code that will stop working in the near future.

## How to fix

Don’t use the deprecated constant or enum case

---

### Running Psalm Issues DeprecatedFunction (`docs/running_psalm/issues/DeprecatedFunction.md`)

# DeprecatedFunction

Emitted when calling a deprecated function:

```php
<?php

/** @deprecated */
function foo() : void {}
foo();
```

## Why this is bad

The `@deprecated` tag is normally indicative of code that will stop working in the near future.

## How to fix

Don’t use the deprecated function.

---

### Running Psalm Issues DeprecatedInterface (`docs/running_psalm/issues/DeprecatedInterface.md`)

# DeprecatedInterface

Emitted when referring to a deprecated interface

```php
<?php

/** @deprecated */
interface I {}

class A implements I {}
```

## Why this is bad

The `@deprecated` tag is normally indicative of code that will stop working in the near future.

## How to fix

Don’t use the deprecated interface.

---

### Running Psalm Issues DeprecatedMethod (`docs/running_psalm/issues/DeprecatedMethod.md`)

# DeprecatedMethod

Emitted when calling a deprecated method on a given class:

```php
<?php

class A {
    /** @deprecated */
    public function foo() : void {}
}
(new A())->foo();
```

## Why this is bad

The `@deprecated` tag is normally indicative of code that will stop working in the near future.

## How to fix

Don’t use the deprecated method.

---

### Running Psalm Issues DeprecatedProperty (`docs/running_psalm/issues/DeprecatedProperty.md`)

# DeprecatedProperty

Emitted when getting/setting a deprecated property of a given class

```php
<?php

class A {
    /**
     * @deprecated
     * @var ?string
     */
    public $foo;
}
(new A())->foo = 5;
```

## Why this is bad

The `@deprecated` tag is normally indicative of code that will stop working in the near future.

## How to fix

Don’t use the deprecated property.

---

### Running Psalm Issues DeprecatedTrait (`docs/running_psalm/issues/DeprecatedTrait.md`)

# DeprecatedTrait

Emitted when referring to a deprecated trait:

```php
<?php

/** @deprecated */
trait T {}
class A {
    use T;
}
```

## Why this is bad

The `@deprecated` tag is normally indicative of code that will stop working in the near future.

## How to fix

Don’t use the deprecated trait.

---

### Running Psalm Issues DirectConstructorCall (`docs/running_psalm/issues/DirectConstructorCall.md`)

# DirectConstructorCall

Emitted when `__construct()` is called directly as a method. Constructors are supposed to be called implicitly, as a result of `new ClassName` statement.

```php
<?php
class A {
    public function __construct() {}
}
$a = new A;
$a->__construct(); // wrong
```

---

### Running Psalm Issues DocblockTypeContradiction (`docs/running_psalm/issues/DocblockTypeContradiction.md`)

# DocblockTypeContradiction

Emitted when conditional doesn't make sense given the docblock types supplied.

```php
<?php

/**
 * @param string $s
 *
 * @return void
 */
function foo($s) {
    if ($s === null) {
        throw new \Exception('Bad input');
    }

    echo $s;
}
```

## Why this is bad

This can sometimes point to a flaw in either your docblock types, or some unnecessary runtime checks in an environment where all types can be checked by Psalm, without the need for additional runtime checks.

## How to fix

A lot of old PHP code is set up to prevent unexpected errors with checks like the one above.

As you migrate your code to newer versions of PHP you can also use stricter type-hints:

```php
<?php

function foo(string $s) : void {
    echo $s;
}
```

Since it's impossible for `$s` to be anything but a `string` inside the function, the null check can be removed.

---

### Running Psalm Issues DuplicateArrayKey (`docs/running_psalm/issues/DuplicateArrayKey.md`)

# DuplicateArrayKey

Emitted when an array has a key more than once

```php
<?php

$arr = [
    'a' => 'one',
    'b' => 'two',
    'c' => 'this text will be overwritten by the next line',
    'c' => 'three',
];
```

This can be caused by variadic arguments if `@no-named-arguments` is not specified:

```php
<?php
function foo($bar, ...$baz): array
{
    return [$bar, ...$baz]; // $baz is array<array-key, mixed> since it can have named arguments
}
```

## How to fix

Remove the offending duplicates:

```php
<?php

$arr = [
    'a' => 'one',
    'b' => 'two',
    'c' => 'three',
];
```

The first matching `'c'` key was removed to prevent a change in behaviour (any new duplicate keys overwrite the values of previous ones).

---

### Running Psalm Issues DuplicateClass (`docs/running_psalm/issues/DuplicateClass.md`)

# DuplicateClass

Emitted when a class is defined twice

```php
<?php

class A {}
class A {}
```

## Why this is bad

The above code won’t compile.

PHP does allow you to define a class conditionally:

```php
<?php

if (rand(0, 1)) {
    class A {
        public function __construct(string $s) {}
    }
} else {
    class A {
        public function __construct(object $o) {}
    }
}
```

But Psalm _really_ doesn't want you to use this pattern – it's impossible for Psalm to know (without using reflection) which class is getting used.

---

### Running Psalm Issues DuplicateConstant (`docs/running_psalm/issues/DuplicateConstant.md`)

# DuplicateConstant

Emitted when a constant is defined twice in a single class or when there's a
clash between a constant and an enum case.

```php
<?php
class C {
    public const A = 1;
    public const A = 2;
}
```

## Why this is bad

The above code won’t compile.

---

### Running Psalm Issues DuplicateEnumCase (`docs/running_psalm/issues/DuplicateEnumCase.md`)

# DuplicateEnumCase

Emitted when enum has duplicate cases.

```php
<?php

enum Status 
{
    case Open;
    case Open;
}
```

## How to fix

Remove or rename the offending duplicates.

```php
<?php

enum Status 
{
    case Open;
    case Closed;
}
```

---

### Running Psalm Issues DuplicateEnumCaseValue (`docs/running_psalm/issues/DuplicateEnumCaseValue.md`)

# DuplicateEnumCaseValue

Emitted when a backed enum has duplicate case values.

```php
<?php

enum Status: string 
{
    case Open = "open";
    case Closed = "open";
}
```

## How to fix

Change case values so that there are no duplicates.

```php
<?php

enum Status: string 
{
    case Open = "open";
    case Closed = "closed";
}
```

---

### Running Psalm Issues DuplicateFunction (`docs/running_psalm/issues/DuplicateFunction.md`)

# DuplicateFunction

Emitted when a function is defined twice

```php
<?php

function foo() : void {}
function bar() : void {}
function foo() : void {}
```

---

### Running Psalm Issues DuplicateMethod (`docs/running_psalm/issues/DuplicateMethod.md`)

# DuplicateMethod

Emitted when a method is defined twice

```php
<?php

class A {
    public function foo() {}
    public function foo() {}
}
```

---

### Running Psalm Issues DuplicateParam (`docs/running_psalm/issues/DuplicateParam.md`)

# DuplicateParam

Emitted when a function has a param defined twice

```php
<?php

function foo(int $b, string $b) {}
```

## Why this is bad

The above code produces a fatal error in PHP.

---

### Running Psalm Issues DuplicateProperty (`docs/running_psalm/issues/DuplicateProperty.md`)

# DuplicateProperty

Emitted when a class property is defined twice

```php
<?php

class Foo
{
    public int $foo;
    public string $foo;
}

class Bar
{
    public int $bar;
    public static string $bar;
}
```

---

### Running Psalm Issues EmptyArrayAccess (`docs/running_psalm/issues/EmptyArrayAccess.md`)

# EmptyArrayAccess

Emitted when attempting to access a value on an empty array

```php
<?php

$a = [];
$b = $a[0];
```

---

### Running Psalm Issues ExtensionRequirementViolation (`docs/running_psalm/issues/ExtensionRequirementViolation.md`)

# ExtensionRequirementViolation

Emitted when a using class of a trait does not extend the class specified using `@psalm-require-extends`.

```php
<?php

class A { }

/**
 * @psalm-require-extends A
 */
trait T { }

class B {
  // ExtensionRequirementViolation is emitted, as T requires
  // the using class B to extend A, which is not the case
  use T; 
}
```

---

### Running Psalm Issues FalsableReturnStatement (`docs/running_psalm/issues/FalsableReturnStatement.md`)

# FalsableReturnStatement

Emitted if a return statement contains a false value, but the function return type does not allow false

```php
<?php

function getCommaPosition(string $a) : int {
    return strpos($a, ',');
}
```

## How to fix

You can add a specific check for false:

```php
<?php

function getCommaPosition(string $a) : int {
    $pos = strpos($a, ',');

    if ($pos === false) {
        return -1;
    }

    return $pos;
}
```

Alternatively you may choose to throw an exception:

```php
<?php

function getCommaPosition(string $a) : int {
    $pos = strpos($a, ',');

    if ($pos === false) {
        throw new Exception('This is unexpected');
    }

    return $pos;
}
```

---

### Running Psalm Issues FalseOperand (`docs/running_psalm/issues/FalseOperand.md`)

# FalseOperand

Emitted when using `false` as part of an operation (e.g. `+`, `.`, `^` etc.)

```php
<?php

echo 5 . false; 
```

## Why this is bad

`false` does not make sense in these operations

---

### Running Psalm Issues ForbiddenCode (`docs/running_psalm/issues/ForbiddenCode.md`)

# ForbiddenCode

Emitted when Psalm encounters a var_dump, exec or similar expression that may make your code more vulnerable

```php
<?php

var_dump("bah");
```

This functions list can be extended by configuring `forbiddenFunctions` or `forbiddenConstants` in `psalm.xml`

```xml
<?xml version="1.0"?>
<psalm>
    

    <forbiddenFunctions>
        <function name="dd"/>
        <function name="var_dump"/>
    </forbiddenFunctions>
    
    <forbiddenConstants>
        <constant name="FILTER_VALIDATE_URL" />
    </forbiddenConstants>
</psalm>
```

---

### Running Psalm Issues IfThisIsMismatch (`docs/running_psalm/issues/IfThisIsMismatch.md`)

# IfThisIsMismatch

Emitted when the type in `@psalm-if-this-is` annotation cannot be contained by the object's actual type.

```php
<?php

/**
 * @template T
 */
class a {
    /**
     * @var T
     */
    private $data;
    /**
     * @param T $data
     */
    public function __construct($data) {
        $this->data = $data;
    }
    /**
     * @psalm-if-this-is a<int>
     */
    public function test(): void {
    }
}

$i = new a(123);
$i->test();

$i = new a("test");
// IfThisIsMismatch - Class is not a<int> as required by psalm-if-this-is
$i->test();
```

---

### Running Psalm Issues ImmutableDependency (`docs/running_psalm/issues/ImmutableDependency.md`)

# ImmutableDependency

Emitted when an mutable class inherits from an immutable class, trait or interface.

```php
<?php

/** @psalm-immutable */
class ImmutableParent {
    public int $i = 0;

    public function getI(): int {
        return $this->i;
    }
}

final class MutableChild extends ImmutableParent {
    public function setI(int $i): void {
        $this->i = 123;
    }
}

// This is bad because when passing around an ImmutableParent instance,
// we might actually be passing around a MutableChild.  
```

Will also be emitted for classes marked `@psalm-pure` or `@psalm-capabilities`, and for a method override that needs more capabilities than the method it overrides:

```php
<?php

abstract class Parent_ {
    /** @psalm-pure */
    abstract public function get(): int;
}

final class Child extends Parent_ {
    /** @psalm-capabilities write-this-props */
    public function get(): int { return 1; } // needs more than the pure method it overrides
}
```

Will also be emitted for a class extending a class with `@psalm-taint-specialize` without having it: the class is specialized, and held to the rules of [specialized classes](../../security_analysis/avoiding_false_positives.md#specializing-taints-in-classes), all the same.

```php
<?php

/** @psalm-taint-specialize */
class User {
    public function __construct(public string $name) {}
}

final class Admin extends User {}
```

To fix, make the child need the same (or fewer) capabilities than the parent, or vice versa.  

See [class-level contracts](../../annotating_code/purity_model.md#class-level-contracts) and [overrides](../../annotating_code/purity_model.md#overrides) in the purity model.

---

### Running Psalm Issues ImplementationRequirementViolation (`docs/running_psalm/issues/ImplementationRequirementViolation.md`)

# ImplementationRequirementViolation

Emitted when a using class of a trait does not implement all interfaces specified using `@psalm-require-implements`.

```php
<?php

interface A { }
interface B { }

/**
 * @psalm-require-implements A
 * @psalm-require-implements B
 */
trait T { }

class C {
  // ImplementationRequirementViolation is emitted, as T requires
  // the using class C to implement A and B, which is not the case
  use T; 
}
```

---

### Running Psalm Issues ImplementedParamTypeMismatch (`docs/running_psalm/issues/ImplementedParamTypeMismatch.md`)

# ImplementedParamTypeMismatch

Emitted when a class that inherits another, or implements an interface, has a docblock param type that's entirely different to the parent.

```php
<?php

class D {
    /** @param string $a */
    public function foo($a): void {}
}

class E extends D {
    /** @param int $a */
    public function foo($a): void {}
}
```

## How to fix

Make sure to respect the [Liskov substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) – any method that overrides a parent method must accept all the same arguments as its parent method.

```php
<?php

class D {
    /** @param string $a */
    public function foo($a): void {}
}

class E extends D {
    /** @param string|int $a */
    public function foo($a): void {}
}
```

---

### Running Psalm Issues ImplementedReturnTypeMismatch (`docs/running_psalm/issues/ImplementedReturnTypeMismatch.md`)

# ImplementedReturnTypeMismatch

Emitted when a class that inherits another, or implements an interface, has a docblock return type that's entirely different to the parent. 

```php
<?php

class A {
    /** @return bool */
    public function foo() {
        return true;
    }
}
class B extends A {
    /** @return string */
    public function foo()  {
        return "hello";
    }
}
```

## How to fix

Make sure to respect the [Liskov substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) – any method that overrides a parent method must return a subtype of the parent method.

In the above case, that means adding the child return type to the parent one.

```php
<?php

class A {
    /** @return bool|string */
    public function foo() {
        return true;
    }
}
class B extends A {
    /** @return string */
    public function foo()  {
        return "hello";
    }
}
```

---

### Running Psalm Issues ImplicitToStringCast (`docs/running_psalm/issues/ImplicitToStringCast.md`)

# ImplicitToStringCast

Emitted when implicitly converting an object with a `__toString` method to a string

```php
<?php

class A {
    public function __toString() {
        return "foo";
    }
}

function takesString(string $s) : void {}

takesString(new A);
```

## How to fix

You can add an explicit string cast:

```php
<?php

...

takesString((string) new A);
```

---

### Running Psalm Issues ImpureByReferenceAssignment (`docs/running_psalm/issues/ImpureByReferenceAssignment.md`)

# ImpureByReferenceAssignment

Emitted when assigning a passed-by-reference variable inside a function or method without the `write-refs` capability.

```php
<?php

/**
 * @psalm-pure
 */
function foo(string &$a): string {
    $a = "B";
    return $a;
}
```

## How to fix

Just remove the mutating assignment:

```php
<?php

/**
 * @psalm-pure
 */
function foo(string &$a): string {
    return $a;
}
```

See [by-reference arguments](../../annotating_code/purity_model.md#by-reference-arguments) in the purity model.

---

### Running Psalm Issues ImpureFunctionCall (`docs/running_psalm/issues/ImpureFunctionCall.md`)

# ImpureFunctionCall

Emitted when calling an impure function from a function or method marked as pure.

```php
<?php

function impure(array $a) : array {
    /** @var int */
    static $i = 0;

    ++$i;

    $a[$i] = 1;

    return $a;
}

/** @psalm-pure */
function filterOdd(array $a) : void {
    impure($a);
}
```

To make a function's purity depend on the closures it is given, see [purity templates](../../annotating_code/purity_model.md#purity-templates) in the purity model.

---

### Running Psalm Issues ImpureGlobalVariable (`docs/running_psalm/issues/ImpureGlobalVariable.md`)

# ImpureGlobalVariable

Emitted when attempting to use a global or superglobal variable from a function or method marked as pure

```php
<?php

/** @psalm-pure */
function getFromSuperglobal() : int {
    return (int) $_GET['v'];
}

/** @psalm-pure */
function addCumulativeGlobal(int $left) : int {
    /** @var int */
    global $i;
    $i ??= 0;
    $i += $left;
    return $left;
}

/** @psalm-pure */
function addCumulativeGlobals(int $left) : int {
    $GLOBALS['i'] ??= 0;
    $GLOBALS['i'] += $left;
    return $left;
}
```

See [capabilities](../../annotating_code/purity_model.md#capabilities) in the purity model for what each capability allows.

---

### Running Psalm Issues ImpureMethodCall (`docs/running_psalm/issues/ImpureMethodCall.md`)

# ImpureMethodCall

Emitted when calling an impure method from a function or method marked as pure.

```php
<?php

class A {
    public int $a = 5;

    public function foo() : void {
        $this->a++;
    }
}

/** @psalm-pure */
function filterOdd(int $i, A $a) : ?int {
    $a->foo();

    if ($i % 2 === 0 || $a->a === 2) {
        return $i;
    }

    return null;
}
```

What a method call costs depends on its receiver: see [how calls are charged](../../annotating_code/purity_model.md#how-calls-are-charged) in the purity model.

---

### Running Psalm Issues ImpurePropertyAssignment (`docs/running_psalm/issues/ImpurePropertyAssignment.md`)

# ImpurePropertyAssignment

Emitted when updating a property value from a function or method marked as pure.

```php
<?php

class A {
    public int $a = 5;
}

/** @psalm-pure */
function foo(int $i, A $a) : int {
    $a->a = $i;

    return $i;
}
```

See [capabilities](../../annotating_code/purity_model.md#capabilities) in the purity model for what each capability allows.

---

### Running Psalm Issues ImpurePropertyFetch (`docs/running_psalm/issues/ImpurePropertyFetch.md`)

# ImpurePropertyFetch

Emitted when fetching a property value inside a function or method marked as pure.

```php
<?php

class A {
    public int $a = 5;
}

/** @psalm-pure */
function foo(int $i, A $a) : int {
    return $i + $a->a;
}
```

See [capabilities](../../annotating_code/purity_model.md#capabilities) in the purity model for what each capability allows.

---

### Running Psalm Issues ImpureStaticProperty (`docs/running_psalm/issues/ImpureStaticProperty.md`)

# ImpureStaticProperty

Emitted when attempting to use a static property from a function or method marked as pure

```php
<?php

class ValueHolder {
    public static ?string $value = null;

    /**
     * @psalm-pure
     */
    public static function get(): ?string {
        return self::$value;
    }
}
```

See [capabilities](../../annotating_code/purity_model.md#capabilities) in the purity model for what each capability allows.

---

### Running Psalm Issues ImpureStaticVariable (`docs/running_psalm/issues/ImpureStaticVariable.md`)

# ImpureStaticVariable

Emitted when attempting to use a static variable from a function or method marked as pure

```php
<?php

/** @psalm-pure */
function addCumulative(int $left) : int {
    /** @var int */
    static $i = 0;
    $i += $left;
    return $left;
}
```

See [capabilities](../../annotating_code/purity_model.md#capabilities) in the purity model for what each capability allows.

---

### Running Psalm Issues ImpureVariable (`docs/running_psalm/issues/ImpureVariable.md`)

# ImpureVariable

Emitted when referencing an impure or possibly-impure variable from a pure context.

```php
<?php

class A {
    public int $a = 5;

    /**
     * @psalm-pure
     */
    public function foo() : self {
        return $this;
    }
}
```

See [capabilities](../../annotating_code/purity_model.md#capabilities) in the purity model for what each capability allows.

---

### Running Psalm Issues InaccessibleClassConstant (`docs/running_psalm/issues/InaccessibleClassConstant.md`)

# InaccessibleClassConstant

Emitted when a public/private class constant is not accessible from the calling context

```php
<?php

class A {
    protected const FOO = 'FOO';
}
echo A::FOO;
```

---

### Running Psalm Issues InaccessibleMethod (`docs/running_psalm/issues/InaccessibleMethod.md`)

# InaccessibleMethod

Emitted when attempting to access a protected/private method from outside its available scope

```php
<?php

class A {
    protected function foo() : void {}
}
echo (new A)->foo();
```

---

### Running Psalm Issues InaccessibleProperty (`docs/running_psalm/issues/InaccessibleProperty.md`)

# InaccessibleProperty

Emitted when attempting to access a protected/private property from outside its available scope

```php
<?php

class A {
    /** @return string */
    protected $foo;
}
echo (new A)->foo;
```

It is also emitted when writing to a property whose asymmetric set visibility (PHP 8.4) is not accessible
from the current context:

```php
<?php

class A {
    public private(set) string $foo = 'bar';
}

$a = new A();
$a->foo = 'baz';
```

---

### Running Psalm Issues IncompatibleTypeParameters (`docs/running_psalm/issues/IncompatibleTypeParameters.md`)

# IncompatibleTypeParameters

Emitted when the constraints recorded for a class template parameter that could not
be inferred at the construction site turn out to be incompatible with each other.

When a templated class is constructed, Psalm tracks each of its templates as a
[type variable](../../annotating_code/type_variables.md): the constructor arguments
and each later use add constraints, which are reconciled with each other once the
surrounding function has been analyzed.

```php
<?php

/** @template T of int */
class IntBox {
    public function __construct() {}

    /** @param T $item */
    public function add($item): void {}
}

function probe(): void {
    $box = new IntBox();
    $box->add("nope");
}
```

Here nothing binds `T` when `IntBox` is constructed, so `T` must be inferred from the
later call to `add()` — but `'nope'` cannot satisfy the template's `of int` constraint.

## Why it’s bad

There is no type the template parameter could take that satisfies all of its
recorded constraints, so the object is being used in contradiction with its
own declaration.

## How to fix

Pass values that satisfy the template's declared constraint:

```php
<?php

/** @template T of int */
class IntBox {
    public function __construct() {}

    /** @param T $item */
    public function add($item): void {}
}

function probe(): void {
    $box = new IntBox();
    $box->add(42);
}
```

---

### Running Psalm Issues InheritorViolation (`docs/running_psalm/issues/InheritorViolation.md`)

# InheritorViolation

Emitted when a class/interface using `@psalm-inheritors` is extended/implemented
by a class that does not fulfil it's requirements.

```php
<?php

/**
 * @psalm-inheritors FooClass|BarClass
 */
class BaseClass {}
class BazClass extends BaseClass {}
// InheritorViolation is emitted, as BaseClass can only be extended
// by FooClass|BarClass, which is not the case
$a = new BazClass();
```

---

### Running Psalm Issues IntMaskComparison (`docs/running_psalm/issues/IntMaskComparison.md`)

# IntMaskComparison

Emitted when a bit set, i.e. a value typed as `int-mask<…>` or `int-mask-of<…>`, is compared by value with something other than `0` or the set of all its bits.

```php
<?php

final class Permission
{
    public const READ = 1;
    public const WRITE = 2;
    public const DELETE = 4;
}

/** @param int-mask-of<Permission::*> $permissions */
function canRead(int $permissions): bool
{
    return $permissions === Permission::READ;
}
```

## Why this is bad

`$permissions === Permission::READ` is only true when `READ` is the *only* bit set: `canRead(Permission::READ | Permission::WRITE)` returns `false`. Comparing a bit set by value is almost always a mistake for a test of some of its bits.

## How to fix

Test the bits you need with `&`:

```php
<?php

final class Permission
{
    public const READ = 1;
    public const WRITE = 2;
    public const DELETE = 4;
}

/** @param int-mask-of<Permission::*> $permissions */
function canRead(int $permissions): bool
{
    return ($permissions & Permission::READ) === Permission::READ;
}
```

- `($mask & B) === B`: every bit of `B` is set;
- `($mask & B) !== 0`: at least one bit of `B` is set;
- `($mask & ~B) === 0`: no bit outside of `B` is set, i.e. the mask is a subset of `B`;
- `$mask === 0`: no bit is set;
- `$mask === ALL`, where `ALL` has every bit of the mask's type: every bit is set.

`$mask & B` is itself a bit set, of the bits of `B`, so it may only be compared with `0` or `B`.

`$a & $b` may also be compared with `$a` or `$b`, as in `($available & $required) === $required`.

The check covers `===`, `!==`, `==`, `!=`, `<`, `<=`, `>`, `>=` and `<=>` (ordering comparisons only allow `0`), `match` arms, `switch` cases, and the search value of `in_array()`, `array_search()` and `array_keys()`.

When a comparison of the exact set of bits is intended, for instance to tell whether a fixed point was reached, pass the masks to a function taking a plain `int` that documents that intent.

---

### Running Psalm Issues InterfaceInstantiation (`docs/running_psalm/issues/InterfaceInstantiation.md`)

# InterfaceInstantiation

Emitted when an attempt is made to instantiate an interface:

```php
<?php

interface I {}
new I();
```

---

### Running Psalm Issues InternalClass (`docs/running_psalm/issues/InternalClass.md`)

# InternalClass

Emitted when attempting to access a class marked as internal an unrelated namespace or class, or attempting
to access a class marked as psalm-internal to a different namespace.

```php
<?php

namespace A {
    /**
     * @internal
     */
    class Foo { }
}

namespace B {
    class Bat {
        public function batBat(): void {
            $a = new \A\Foo();
        }
    }
}
```

---

### Running Psalm Issues InternalMethod (`docs/running_psalm/issues/InternalMethod.md`)

# InternalMethod

Emitted when attempting to access a method marked as internal an unrelated namespace or class, or attempting
to access a method marked as psalm-internal to a different namespace.

```php
<?php

namespace A {
    class Foo {
        /**
         * @internal
         */
        public static function barBar(): void {
        }
    }
}
namespace B {
    class Bat {
        public function batBat(): void {
            \A\Foo::barBar();
        }
    }
}
```

---

### Running Psalm Issues InternalProperty (`docs/running_psalm/issues/InternalProperty.md`)

# InternalProperty

Emitted when attempting to access a property marked as internal from an unrelated namespace or class, or attempting
to access a property marked as psalm-internal to a different namespace.

```php
<?php

namespace A {
    class Foo {
        /**
         * @internal
         * @var ?int
         */
        public $foo;
    }
}

namespace B {
    class Bat {
        public function batBat() : void {
            echo (new \A\Foo)->foo;
        }
    }
}
```

---

### Running Psalm Issues InvalidArgument (`docs/running_psalm/issues/InvalidArgument.md`)

# InvalidArgument

Emitted when a supplied function/method argument is incompatible with the method signature or docblock one.

```php
<?php

class A {}

function foo(A $a) : void {}

/**
 * @param string $s
 */
function callFoo($s) : void {
    foo($s);
}
```

## Why it’s bad

Calling functions with incorrect values will cause a fatal error at runtime.

## How to fix

Sometimes this message can just be the result of an incorrect docblock.

You can fix by correcting the docblock, or converting to a function signature:

```php
<?php

class A {}

function foo(A $a) : void {}

function callFoo(A $a) : void {
    foo($a);
}
```

---

### Running Psalm Issues InvalidArrayAccess (`docs/running_psalm/issues/InvalidArrayAccess.md`)

# InvalidArrayAccess

Emitted when attempting to access an array offset on a value that does not permit it

```php
<?php

$arr = 5;
echo $arr[0];
```

---

### Running Psalm Issues InvalidArrayAssignment (`docs/running_psalm/issues/InvalidArrayAssignment.md`)

# InvalidArrayAssignment

Emitted when attempting to assign a value on a non-array

```php
<?php

$arr = 5;
$arr[0] = 3;
```

---

### Running Psalm Issues InvalidArrayOffset (`docs/running_psalm/issues/InvalidArrayOffset.md`)

# InvalidArrayOffset

Emitted when attempting to access an array using a value that's not a valid offset for that array

```php
<?php

$a = [5, 20, 18];
echo $a["hello"];
```

---

### Running Psalm Issues InvalidAttribute (`docs/running_psalm/issues/InvalidAttribute.md`)

# InvalidAttribute

Emitted when using an attribute on an element that doesn't match the attribute's target

```php
<?php
namespace Foo;

#[\Attribute(\Attribute::TARGET_CLASS)]
class Table {
    public function __construct(public string $name) {}
}

#[Table("videos")]
function foo() : void {}
```

---

### Running Psalm Issues InvalidCast (`docs/running_psalm/issues/InvalidCast.md`)

# InvalidCast

Emitted when attempting to cast a value that's not castable

```php
<?php

class A {}
$a = new A();
$b = (string)$a;
```

---

### Running Psalm Issues InvalidCatch (`docs/running_psalm/issues/InvalidCatch.md`)

# InvalidCatch

Emitted when trying to catch a class/interface that doesn't extend `Exception` or implement `Throwable`

```php
<?php

class A {}
try {
    $worked = true;
}
catch (A $e) {}
```

---

### Running Psalm Issues InvalidClass (`docs/running_psalm/issues/InvalidClass.md`)

# InvalidClass

Emitted when referencing a class with the wrong casing

```php
<?php

class Foo {}
(new foo());
```

Could also be an issue in the namespace even if the class has the correct casing
```php
<?php

namespace OneTwo {
    class Three {}
}

namespace {
    use Onetwo\Three;
    //     ^ ("t" instead of "T")

    $three = new Three();
}
```

---

### Running Psalm Issues InvalidClassConstantType (`docs/running_psalm/issues/InvalidClassConstantType.md`)

# InvalidClassConstantType

Emitted when a constant type in a child does not satisfy the type in the parent.

```php
<?php

class Foo
{
    /** @var int<1,max> */
    public const CONSTANT = 3;

    public static function bar(): array
    {
        return str_split("foobar", static::CONSTANT);
    }
}

class Bar extends Foo
{
    /** @var int<min,-1> */
    public const CONSTANT = -1;
}

Bar::bar(); // Error: str_split argument 2 must be greater than 0
```

This issue will always show up when overriding a constant that doesn't have a docblock type. Psalm will infer the most specific type for the constant that it can, you have to add a type annotation to tell it what type constraint you wish to be applied. Otherwise Psalm has no way of telling if you mean for the constant to be a literal `1`, `int<1, max>`, `int`, `numeric`, etc.

---

### Running Psalm Issues InvalidClone (`docs/running_psalm/issues/InvalidClone.md`)

# InvalidClone

Emitted when trying to clone a value that's not cloneable

```php
<?php

$a = "hello";
$b = clone $a;
```

---

### Running Psalm Issues InvalidConstantAssignmentValue (`docs/running_psalm/issues/InvalidConstantAssignmentValue.md`)

# InvalidConstantAssignmentValue

Emitted when attempting to assign a value to a class constant that cannot contain that type.

```php
<?php

class Foo {
    /** @var int */
    public const BAR = "bar";
}
```

---

### Running Psalm Issues InvalidDocblock (`docs/running_psalm/issues/InvalidDocblock.md`)

# InvalidDocblock

Emitted when there's an error in a docblock type

```php
<?php

/** @var array() */
$a = [];
```

---

### Running Psalm Issues InvalidDocblockParamName (`docs/running_psalm/issues/InvalidDocblockParamName.md`)

# InvalidDocblockParamName

Emitted when a docblock param name does not match up with a named param in the function, if the param does not have a type or its type is `array`.

```php
<?php

/**
 * @param string[] $bar
 */
function foo(array $barb): void {
    //
}
```

---

### Running Psalm Issues InvalidEnumBackingType (`docs/running_psalm/issues/InvalidEnumBackingType.md`)

# InvalidEnumBackingType

Enums can only be backed by `int` or `string`. Emitted when an enum is backed
by something else.

```php
<?php

enum Status: array 
{
   case None = [];
}
```

---

### Running Psalm Issues InvalidEnumCaseValue (`docs/running_psalm/issues/InvalidEnumCaseValue.md`)

# InvalidEnumCaseValue

Emitted when case value is invalid (see below).

## Case with a value on a pure enum

```php
<?php

enum Status 
{
    case Open = "open";
}
```

### How to fix

Either remove the value or alter the enum to be backed.

```php
<?php

enum Status: string 
{
    case Open = "open";
}
```

## Case without a value on a backed enum

```php
<?php

enum Status: string 
{
    case Open;    
}
```

### How to fix

Either alter the enum to be pure, or add a value.

```php
<?php

enum Status 
{
    case Open;
}
```

## Case type mismatch

Case type should match the backing type of the enum.

```php
<?php

enum Status: string
{
    case Open = 1;
}
```

### How to fix

Change the types so that they match

```php
<?php

enum Status: string 
{
    case Open = "open";
}
```

## Case with a type that cannot back an enum

Case type should be either `int` or `string`.

```php
<?php

enum Status: int {
    case Open = [];
}
```

### How to fix

Change the case value so that it's one of the allowed types (and matches the backing type)

```php
<?php

enum Status: int
{
    case Open = 1;
}
```

---

### Running Psalm Issues InvalidEnumMethod (`docs/running_psalm/issues/InvalidEnumMethod.md`)

# InvalidEnumMethod

Enums may not define most of the magic methods like `__get`, `__toString`, etc.

```php
<?php
enum Status: string {
    case Open = 'open';
    case Closed = 'closed';

    public function __toString(): string {
        return "SomeStatus";
    }
}
```

---

### Running Psalm Issues InvalidExtendClass (`docs/running_psalm/issues/InvalidExtendClass.md`)

# InvalidExtendClass

Emitted when attempting to extend a final class, a class annotated with `@final` or a class using @psalm-inheritors and not in the inheritor list

```php
<?php

final class A {}

class B extends A {}

/**
 * @final
 */
class DoctrineA {}

class DoctrineB extends DoctrineA {}

/**
 * @psalm-inheritors A|B
 */
class C {}

class D extends C {}
```

---

### Running Psalm Issues InvalidFalsableReturnType (`docs/running_psalm/issues/InvalidFalsableReturnType.md`)

# InvalidFalsableReturnType

Emitted when a function can return a nullable value, but its given return type says otherwise

```php
<?php

function foo() : string {
    if (rand(0, 1)) {
        return "foo";
    }

    return false;
}
```

---

### Running Psalm Issues InvalidFunctionCall (`docs/running_psalm/issues/InvalidFunctionCall.md`)

# InvalidFunctionCall

Emitted when calling a function on a non-callable variable

```php
<?php

$a = 5;
$b = $a();
```

---

### Running Psalm Issues InvalidGlobal (`docs/running_psalm/issues/InvalidGlobal.md`)

# InvalidGlobal

Emitted when there's a reference to the global keyword where it's not expected.

```php
<?php

global $e;
```

If the file is included from a non-global scope this issue will have to be suppressed. See
[Config suppression](../../dealing_with_code_issues/#suppressing-issues) for how to suppress this at the file or directory
level.

---

### Running Psalm Issues InvalidInterfaceImplementation (`docs/running_psalm/issues/InvalidInterfaceImplementation.md`)

# InvalidInterfaceImplementation

Emitted when trying to implement interface that cannot be implemented (e.g. `Throwable`, `UnitEnum`, `BackedEnum`).

```php
<?php

class E implements UnitEnum 
{
    public static function cases(): array 
    {
        return []; 
    }
}
```

---

### Running Psalm Issues InvalidIterator (`docs/running_psalm/issues/InvalidIterator.md`)

# InvalidIterator

Emitted when trying to iterate over a value that's not iterable

```php
<?php

$a = 5;
foreach ($a as $b) {}
```

---

### Running Psalm Issues InvalidLiteralArgument (`docs/running_psalm/issues/InvalidLiteralArgument.md`)

# InvalidLiteralArgument

Emitted when a literal argument is passed where a variable is expected, such as the first argument of `strpos`, where an explicit `$haystack` is almost always unintended.

```php
<?php

function foo(string $s) : void {
    echo strpos(".", $s);
}
```

---

### Running Psalm Issues InvalidMethodCall (`docs/running_psalm/issues/InvalidMethodCall.md`)

# InvalidMethodCall

Emitted when attempting to call a method on a non-object

```php
<?php

$a = 5;
$a->foo();
```

---

### Running Psalm Issues InvalidNamedArgument (`docs/running_psalm/issues/InvalidNamedArgument.md`)

# InvalidNamedArgument

Emitted when a supplied function/method argument name is incompatible with the function/method signature.

```php
<?php

function takesArguments(string $name, int $age) : void {}

takesArguments(name: "hello", ag: 5);
```

---

### Running Psalm Issues InvalidNullableReturnType (`docs/running_psalm/issues/InvalidNullableReturnType.md`)

# InvalidNullableReturnType

Emitted when a function can return a nullable value, but its given return type says otherwise

```php
<?php

function foo() : string {
    if (rand(0, 1)) {
        return "foo";
    }

    return null;
}
```

---

### Running Psalm Issues InvalidOperand (`docs/running_psalm/issues/InvalidOperand.md`)

# InvalidOperand

Emitted when using something as an operand that is unexpected

```php
<?php

class A {}
echo (new A) . ' ';
```

---

### Running Psalm Issues InvalidOverride (`docs/running_psalm/issues/InvalidOverride.md`)

# InvalidOverride

Emitted when an `Override` attribute was added to a method that does not override a method from a parent class or implemented interface.

```php
<?php

class A {
    function receive(): void
    {
    }
}

class B extends A {
    #[Override]
    function obtain(): void
    {
    }
}
```

## Why this is bad

A fatal error will be thrown.

---

### Running Psalm Issues InvalidParamDefault (`docs/running_psalm/issues/InvalidParamDefault.md`)

# InvalidParamDefault

Emitted when a function parameter default clashes with the type Psalm expects the param to be

```php
<?php

function foo(int $i = false) : void {}
```

---

### Running Psalm Issues InvalidParent (`docs/running_psalm/issues/InvalidParent.md`)

# InvalidParent

Emitted when a function return type is `parent`, but there's no parent class
```php
<?php

class Foo {
    public function f(): parent {}
}
```

---

### Running Psalm Issues InvalidPassByReference (`docs/running_psalm/issues/InvalidPassByReference.md`)

# InvalidPassByReference

Emitted when passing a non-variable to a function that expects a by-ref variable

```php
<?php

function foo(array &$arr) : void {}
foo([0, 1, 2]);
```

---

### Running Psalm Issues InvalidPropertyAssignment (`docs/running_psalm/issues/InvalidPropertyAssignment.md`)

# InvalidPropertyAssignment

Emitted when attempting to assign a property to a non-object

```php
<?php

$a = "foo";
$a->bar = "bar";
```

---

### Running Psalm Issues InvalidPropertyAssignmentValue (`docs/running_psalm/issues/InvalidPropertyAssignmentValue.md`)

# InvalidPropertyAssignmentValue

Emitted when attempting to assign a value to a property that cannot contain that type.

```php
<?php

class A {
    /** @var string|null */
    public $foo;
}
$a = new A();
$a->foo = new stdClass();
```

---

### Running Psalm Issues InvalidPropertyFetch (`docs/running_psalm/issues/InvalidPropertyFetch.md`)

# InvalidPropertyFetch

Emitted when attempting to get a property from a non-object

```php
<?php

$a = "foo";
echo $a->bar;
```

---

### Running Psalm Issues InvalidReturnStatement (`docs/running_psalm/issues/InvalidReturnStatement.md`)

# InvalidReturnStatement

Emitted when a function return statement is incorrect

```php
<?php

function foo() : string {
    return 5; // emitted here
}
```

---

### Running Psalm Issues InvalidReturnType (`docs/running_psalm/issues/InvalidReturnType.md`)

# InvalidReturnType

Emitted when a function’s signature return type is incorrect (often emitted with `InvalidReturnStatement`)

```php
<?php

function foo() : int {
    if (rand(0, 1)) {
        return "hello";
    }

    return 5;
}
```

---

### Running Psalm Issues InvalidScalarArgument (`docs/running_psalm/issues/InvalidScalarArgument.md`)

# InvalidScalarArgument

Emitted when a scalar value is passed to a method that expected another scalar type.

This is only emitted in situations where Psalm can be sure that PHP tries to coerce one scalar type to another.

In all other cases `InvalidArgument` is emitted.

```php
<?php

function foo(int $i) : void {}
function bar(string $s) : void {
    if (is_numeric($s)) {
        foo($s);
    }
}
```

---

### Running Psalm Issues InvalidScope (`docs/running_psalm/issues/InvalidScope.md`)

# InvalidScope

Emitted when referring to `$this` outside a class

```php
<?php

echo $this;
```

---

### Running Psalm Issues InvalidStaticInvocation (`docs/running_psalm/issues/InvalidStaticInvocation.md`)

# InvalidStaticInvocation

Emitted when trying to call an instance function statically

```php
<?php

class A {
    /** @var ?string */
    public $foo;

    public function bar() : void {
        echo $this->foo;
    }
}

A::bar();
```

---

### Running Psalm Issues InvalidStringClass (`docs/running_psalm/issues/InvalidStringClass.md`)

# InvalidStringClass

Emitted when you have `allowStringToStandInForClass="false"` in your config and you’re passing a string instead of calling a class directly

```php
<?php

class Foo {}
$a = "Foo";
new $a();
```

---

### Running Psalm Issues InvalidTemplateParam (`docs/running_psalm/issues/InvalidTemplateParam.md`)

# InvalidTemplateParam

Emitted when using the `@extends`/`@implements` annotation to extend a class that has a template type constraint, where that extended value does not satisfy the parent class/interface's constraints.

```php
<?php

/**
 * @template T of object
 */
class Base {}

/** @template-extends Base<int> */
class SpecializedByInheritance extends Base {}
```

---

### Running Psalm Issues InvalidThrow (`docs/running_psalm/issues/InvalidThrow.md`)

# InvalidThrow

Emitted when trying to throw a class that doesn't extend `Exception` or implement `Throwable`

```php
<?php

class A {}
throw new A();
```

---

### Running Psalm Issues InvalidToString (`docs/running_psalm/issues/InvalidToString.md`)

# InvalidToString

Emitted when a `__toString` method does not always return a `string`

```php
<?php

class A {
    public function __toString() {
        /** @psalm-suppress InvalidReturnStatement */
        return true;
    }
}
```

---

### Running Psalm Issues InvalidTraversableImplementation (`docs/running_psalm/issues/InvalidTraversableImplementation.md`)

# InvalidTraversableImplementation

Emitted when class incorrectly implements Traversable. Traversable needs to be
implemented by implementing either `IteratorAggregate` or `Iterator`

```php
<?php

/**
 * @implements Traversable<mixed, mixed>
 */
final class C implements Traversable {} // will cause fatal error
```

---

### Running Psalm Issues InvalidTypeImport (`docs/running_psalm/issues/InvalidTypeImport.md`)

# InvalidTypeImport

Emitted when a type imported with `@psalm-import-type` is invalid

```php
<?php

namespace A;

class Types {}

namespace B;
use A\Types;
/** @psalm-import-type UnknownType from Types */
class C {}
```

---

### Running Psalm Issues LessSpecificClassConstantType (`docs/running_psalm/issues/LessSpecificClassConstantType.md`)

# LessSpecificClassConstantType

Emitted when a constant type in a child is less specific than the type in the parent.

```php
<?php

class Foo
{
    /** @var int<1,max> */
    public const CONSTANT = 3;

    public static function bar(): array
    {
        return str_split("foobar", static::CONSTANT);
    }
}

class Bar extends Foo
{
    /** @var int */
    public const CONSTANT = -1;
}

Bar::bar(); // Error: str_split argument 2 must be greater than 0
```

This issue will always show up when overriding a constant that doesn't have a docblock type. Psalm will infer the most specific type for the constant that it can, you have to add a type annotation to tell it what type constraint you wish to be applied. Otherwise Psalm has no way of telling if you mean for the constant to be a literal `1`, `int<1, max>`, `int`, `numeric`, etc.

---

### Running Psalm Issues LessSpecificImplementedReturnType (`docs/running_psalm/issues/LessSpecificImplementedReturnType.md`)

# LessSpecificImplementedReturnType

Emitted when a class implements an interface method but its return type is less specific than the interface method return type

```php
<?php

class A {}
class B extends A {}
interface I {
    /** @return B[] */
    public function foo();
}
class D implements I {
    /** @return A[] */
    public function foo() {
        return [new A, new A];
    }
}
```

---

### Running Psalm Issues LessSpecificReturnStatement (`docs/running_psalm/issues/LessSpecificReturnStatement.md`)

# LessSpecificReturnStatement

Emitted when a return statement is more general than the return type given for the function

```php
<?php

class A {}
class B extends A {}

function foo() : B {
    return new A(); // emitted here
}
```

---

### Running Psalm Issues LessSpecificReturnType (`docs/running_psalm/issues/LessSpecificReturnType.md`)

# LessSpecificReturnType

Emitted when a return type covers more possibilities than the function itself

```php
<?php

function foo() : ?int {
    return 5;
}
```

---

### Running Psalm Issues LiteralKeyUnshapedArray (`docs/running_psalm/issues/LiteralKeyUnshapedArray.md`)

# LiteralKeyUnshapedArray

Emitted when a literal key is used on an unshaped array, enabled by the [disallowLiteralKeysOnUnshapedArrays](https://psalm.dev/docs/running_psalm/configuration/#disallowliteralkeysonunshapedarrays) config parameter.  

Useful to enforce usage of [shaped arrays](https://psalm.dev/docs/annotating_code/type_syntax/array_types/#object-like-arrays) instead of [generic arrays](https://psalm.dev/docs/annotating_code/type_syntax/array_types/#object-like-arrays).  

```php
<?php

/**
 * @param array<string, bool> $arr
 */
function takesGenericArr(array $arr): void {
    // Error: LiteralKeyUnshapedArray
    $flagA = $arr['flagA'];
    // Error: LiteralKeyUnshapedArray
    $flagB = $arr['flagB'];
}

/**
 * @param array{flagA: bool, flagB: bool} $arr
 */
function takesShapedArr(array $arr): void {
    // OK
    $flagA = $arr['flagA'];
    // OK
    $flagB = $arr['flagB'];
}
```

---

### Running Psalm Issues LoopInvalidation (`docs/running_psalm/issues/LoopInvalidation.md`)

# LoopInvalidation

Emitted when logic inside a loop invalidates one of the conditionals of the loop

```php
<?php

for ($i = 0; $i < 10; $i++) {
    $i = 5;
}
```

---

### Running Psalm Issues MethodSignatureMismatch (`docs/running_psalm/issues/MethodSignatureMismatch.md`)

# MethodSignatureMismatch

Emitted when a method parameter differs from a parent method parameter, or if there are fewer parameters than the parent method

```php
<?php

class A {
    public function foo(int $i) : void {}
}
class B extends A {
    public function foo(string $i) : void {}
}
```

---

### Running Psalm Issues MethodSignatureMustOmitReturnType (`docs/running_psalm/issues/MethodSignatureMustOmitReturnType.md`)

# MethodSignatureMustOmitReturnType

Emitted when a `__clone`, `__construct`, or `__destruct` method is defined with a return type.

```php
<?php

class A {
    public function __clone() : void {}
}
```

---

### Running Psalm Issues MethodSignatureMustProvideReturnType (`docs/running_psalm/issues/MethodSignatureMustProvideReturnType.md`)

# MethodSignatureMustProvideReturnType

In PHP 8.1+, [most non-final internal methods now require overriding methods to declare a compatible return type, otherwise a deprecated notice is emitted during inheritance validation](https://www.php.net/manual/en/migration81.incompatible.php#migration81.incompatible.core.type-compatibility-internal).  

This issue is emitted when a method overriding a native method is defined without a return type.  

**Only if** the return type cannot be declared to keep support for PHP 7, a `#[ReturnTypeWillChange]` attribute can be added to silence the PHP deprecation notice and Psalm issue.  

```php
<?php
class A implements JsonSerializable {
    public function jsonSerialize() {
        return ['type' => 'A'];
    }
}
```

---

### Running Psalm Issues MismatchingDocblockParamType (`docs/running_psalm/issues/MismatchingDocblockParamType.md`)

# MismatchingDocblockParamType

Emitted when an `@param` entry in a function’s docblock does not match the param typehint

```php
<?php

/**
 * @param int $b
 */
function foo(string $b) : void {}
```

---

### Running Psalm Issues MismatchingDocblockPropertyType (`docs/running_psalm/issues/MismatchingDocblockPropertyType.md`)

# MismatchingDocblockPropertyType

Emitted when an `@var` entry in a property’s docblock does not match the property's type.

```php
<?php
class A {
    /** @var array */
    public string $s = [];
}
```

---

### Running Psalm Issues MismatchingDocblockReturnType (`docs/running_psalm/issues/MismatchingDocblockReturnType.md`)

# MismatchingDocblockReturnType

Emitted when an `@return` entry in a function’s docblock does not match the function return typehint

```php
<?php

class A {}
class B {}
/**
 * @return B // emitted here
 */
function foo() : A {
    return new A();
}
```

This, however, is fine:

```php
<?php

class A {}
class B extends A {}
/**
 * @return B // emitted here
 */
function foo() : A {
    return new B();
}
```

---

### Running Psalm Issues MissingAbstractPureAnnotation (`docs/running_psalm/issues/MissingAbstractPureAnnotation.md`)

# MissingAbstractPureAnnotation

Emitted when an abstract method does not have a `@psalm-pure`, `@psalm-impure` or [`@psalm-capabilities`](../../annotating_code/supported_annotations.md#psalm-capabilities)
annotation, which says what every implementation may do, for example:

* `@psalm-pure` - no side effects and no property accesses
* `@psalm-capabilities read-props` - may read properties, but not write them
* `@psalm-capabilities read-props|write-this-props` - may also write the properties of `$this`
* `@psalm-impure` - may do anything (not recommended)

This issue is emitted to aid [security analysis](https://psalm.dev/docs/security_analysis/), which works best when all explicitly pure functions and methods are marked as pure.  

```php
<?php

interface a {
    public function someMethod(): void;
}
```

See [class-level contracts](../../annotating_code/purity_model.md#class-level-contracts) in the purity model.

---

### Running Psalm Issues MissingClassConstType (`docs/running_psalm/issues/MissingClassConstType.md`)

# MissingClassConstType

Emitted when a class constant doesn't have a declared type.

```php
<?php

class A {
    public const B = 0;
}
```

Correct with:

```php
<?php

class A {
    public const int B = 0;
}
```

---

### Running Psalm Issues MissingClosureParamType (`docs/running_psalm/issues/MissingClosureParamType.md`)

# MissingClosureParamType

Emitted when a closure parameter has no type information associated with it

```php
<?php

$a = function($a): string {
    return "foo";
};
```

---

### Running Psalm Issues MissingClosureReturnType (`docs/running_psalm/issues/MissingClosureReturnType.md`)

# MissingClosureReturnType

Emitted when a closure lacks a return type

```php
<?php

$a = function() {
    return "foo";
};
```

---

### Running Psalm Issues MissingConstructor (`docs/running_psalm/issues/MissingConstructor.md`)

# MissingConstructor

Uninitialized properties are statically hard to analyze. To prevent mistakes, Psalm will enforce that all properties should be initialized.

It does that through [PropertyNotSetInConstructor](./PropertyNotSetInConstructor.md) and this issue.

Psalm will then assume every property in the codebase is initialized.

Doing that allows it to report missing initializations as well as [RedundantPropertyInitializationCheck](./RedundantPropertyInitializationCheck.md)

This issue is emitted when non-null properties without default values are defined in a class without a `__construct` method

If your project relies on having uninitialized properties, it is advised to suppress this issue, as well as [PropertyNotSetInConstructor](./PropertyNotSetInConstructor.md) and [RedundantPropertyInitializationCheck](./RedundantPropertyInitializationCheck.md).

```php
<?php

class A {
    /** @var string */
    public $foo;
}
```

---

### Running Psalm Issues MissingDependency (`docs/running_psalm/issues/MissingDependency.md`)

# MissingDependency

Emitted when referencing a class that does not exist

```php
<?php

/**
 * @psalm-suppress UndefinedClass
 */
class A extends B {}

$a = new A();
```

---

### Running Psalm Issues MissingDocblockType (`docs/running_psalm/issues/MissingDocblockType.md`)

# MissingDocblockType

Emitted when a docblock is present, but the type is missing or badly formatted

```php
<?php

/** @var $a */
$a = [];
```

---

### Running Psalm Issues MissingFile (`docs/running_psalm/issues/MissingFile.md`)

# MissingFile

Emitted when using `include` or `require` on a file that does not exist

```php
<?php

require("nonexistent.php");
```

---

### Running Psalm Issues MissingImmutableAnnotation (`docs/running_psalm/issues/MissingImmutableAnnotation.md`)

# MissingImmutableAnnotation

Emitted when a potentially immutable interface or class does not have a `@psalm-pure`, `@psalm-immutable` or `@psalm-capabilities` declaration.  

To automatically add immutable annotations where needed, run Psalm with `--alter --issues=MissingImmutableAnnotation`.  

This issue is emitted to aid [security analysis](https://psalm.dev/docs/security_analysis/), which works best when all explicitly immutable interfaces and classes are marked as immutable.  

```php
<?php

/** @api */
final class CouldBeExternallyMutationFree {
    private int $counter = 0;

    /** @psalm-capabilities read-props|write-this-props */
    public function someInteger() : int {
        return ++$this->counter;
    }
}

/** @api */
final class CouldBeImmutable {
}

```

See [inferring annotations](../../annotating_code/purity_model.md#inferring-annotations) in the purity model.

---

### Running Psalm Issues MissingInterfaceImmutableAnnotation (`docs/running_psalm/issues/MissingInterfaceImmutableAnnotation.md`)

# MissingInterfaceImmutableAnnotation

Emitted when an interface is not annotated with `@psalm-pure`, `@psalm-immutable`, `@psalm-capabilities` or `@psalm-mutable`, and declares a method without a purity annotation of its own (or a `@psalm-purity-from-template`): to fix, mark the interface with one of them, which then applies to all properties and methods of implementing classes. An interface whose methods all say what they may do needs no class-level annotation. Nor does a marker interface, which declares no method or property and inherits none: it does nothing, so it is pure, without capping its implementers.

This issue is emitted to aid [security analysis](https://psalm.dev/docs/security_analysis/), which works best when all explicitly immutable interfaces and classes are marked as immutable.  

```php
<?php

/** @api */
interface SomethingPotentiallyImmutable {
    public function someInteger() : int;
}

final class A implements SomethingPotentiallyImmutable {
    public function someInteger() : int {
        return 0;
    }
}
```

See [class-level contracts](../../annotating_code/purity_model.md#class-level-contracts) in the purity model.

---

### Running Psalm Issues MissingOverrideAttribute (`docs/running_psalm/issues/MissingOverrideAttribute.md`)

# MissingOverrideAttribute

Emitted when the config flag `ensureOverrideAttribute` is set to `true` and a method on a child class or interface overrides a method on a parent, but no `Override` attribute is present.

```php
<?php

class A {
    function receive(): void
    {
    }
}

class B extends A {
    function receive(): void
    {
    }
}
```

## Why this is bad

Having an `Override` attribute on overridden methods makes intentions clear. Read the [PHP RFC](https://wiki.php.net/rfc/marking_overriden_methods) for more details.

## How to fix

Declare the `#[\Override]` attribute on all indicated methods, or run `vendor/bin/psalter --issues=MissingOverrideAttribute` to let Psalm do it for you.  

Note that the `#[\Override]` attribute is compatible with **all PHP versions**, even PHP 4.  

On PHP 8.0-8.2, require [symfony/polyfill-php83](https://packagist.org/packages/symfony/polyfill-php83) to polyfill the missing Override attribute.

---

### Running Psalm Issues MissingParamType (`docs/running_psalm/issues/MissingParamType.md`)

# MissingParamType

Emitted when a function parameter has no type information associated with it

```php
<?php

function foo($a) : void {}
```

---

### Running Psalm Issues MissingPropertyType (`docs/running_psalm/issues/MissingPropertyType.md`)

# MissingPropertyType

Emitted when a property is defined on a class without a type

```php
<?php

class A {
    public $foo = 5;
}
```

This feature is available in PHP since version 7.4

For more information see:
* [Properties](https://www.php.net/manual/en/language.oop5.properties.php) in the PHP manual.
* PHP RFC: [Typed Properties 2.0](https://wiki.php.net/rfc/typed_properties_v2)

---

### Running Psalm Issues MissingPureAnnotation (`docs/running_psalm/issues/MissingPureAnnotation.md`)

# MissingPureAnnotation

Emitted when a potentially pure function or method does not have a `@psalm-pure` or `@psalm-capabilities` declaration: the issue suggests the capabilities it was inferred to need.  

A function-like explicitly marked `@psalm-impure` is left alone: for example a hook that overriding methods may implement freely.  

No annotation is suggested for an unannotated method that is overridden, nor for the code calling it: the overrides may do more than its own body does, and the annotation would restrict them.  

No annotation is suggested for a function-like whose parameter default values need capabilities the annotation would not give them (see [parameter default values](../../annotating_code/purity_model.md#parameter-default-values)).  

To automatically add pure annotations where needed, run Psalm with `--alter --issues=MissingPureAnnotation`.  

This issue is emitted to aid [security analysis](https://psalm.dev/docs/security_analysis/), which works best when all explicitly pure functions and methods are marked as pure.  

```php
<?php

function couldBePure(int $a): int {
    return $a+1;
}
```

A function or method (not a closure) is inferred without what the `_` purity of its parameters (`Closure[_]`, `Traversable[_]`, see [`@psalm-purity-template`](../../annotating_code/supported_annotations.md#psalm-purity-template)) would charge to its callers: calling the closures and callables found in a parameter with the default purity, directly (`$f()`), in its elements (`$fs[0]()`, `foreach ($fs as $f) { $f(); }`) or in what they return (`$f()()`); iterating over an iterable parameter; and calling a method whose purity depends on a purity argument of a parameter (`Doer[_]` for a `Doer` with a `@psalm-purity-template`). The issue then names the parameters, and `--alter` adds the `_` where it stands, along with the purity annotation.

```php
<?php

/**
 * @param list<Closure(int): int> $fs
 */
function applyAll(array $fs, int $x): int {
    foreach ($fs as $f) {
        $x = $f($x); // with --alter, $fs becomes list<Closure[_](int): int> and applyAll @psalm-pure
    }
    return $x;
}
```

Only what the function-like's own body does counts, not what the closures it creates do: those may be returned or stored rather than called. The parameter must not be assigned in the body, and the `_` must be writable where the parameter's type is written (not behind a `@psalm-type` alias, and not where another purity is written).

See [inferring annotations](../../annotating_code/purity_model.md#inferring-annotations) in the purity model for how purity is inferred.

---

### Running Psalm Issues MissingReturnType (`docs/running_psalm/issues/MissingReturnType.md`)

# MissingReturnType

Emitted when a function doesn't have a return type defined

```php
<?php

function foo() {
    return "foo";
}
```

Correct with:

```php
<?php

function foo() : string {
    return "foo";
}
```

---

### Running Psalm Issues MissingTemplateParam (`docs/running_psalm/issues/MissingTemplateParam.md`)

# MissingTemplateParam

Emitted when using the `@extends`/`@implements` annotation to extend a class without
extending all its template params.

```php
<?php

/**
 * @template-implements ArrayAccess<int>
 */
class SomeIterator implements ArrayAccess
{
    public function offsetSet($offset, $value) {
    }

    public function offsetExists($offset) {
        return false;
    }

    public function offsetUnset($offset) {
    }

    public function offsetGet($offset) {
        return null;
    }
}
```

---

### Running Psalm Issues MissingThrowsDocblock (`docs/running_psalm/issues/MissingThrowsDocblock.md`)

# MissingThrowsDocblock

Enabled when the `checkForThrowsDocblock` configuration option is enabled.

Emitted when a function throws (or fails to handle) an exception and does not have a `@throws` annotation.

```php
<?php

function foo(int $x, int $y) : int {
    if ($y === 0) {
        throw new \InvalidArgumentException('Cannot divide by zero');
    }

    return intdiv($x, $y);
}
```

---

### Running Psalm Issues MixedArgument (`docs/running_psalm/issues/MixedArgument.md`)

# MixedArgument

Emitted when Psalm cannot determine the type of an argument

```php
<?php

function takesInt(int $i) : void {}
takesInt($GLOBALS['foo']);
```

---

### Running Psalm Issues MixedArgumentTypeCoercion (`docs/running_psalm/issues/MixedArgumentTypeCoercion.md`)

# MixedArgumentTypeCoercion

Emitted when Psalm cannot be sure that part of an array/iterable argument's type constraints can be fulfilled

```php
<?php

function foo(array $a) : void {
    takesStringArray($a);
}

/** @param string[] $a */
function takesStringArray(array $a) : void {}
```

This can happen with variadic arguments when `@no-named-arguments` is not specified:

```php
<?php

/** @param list<int> $args */
function foo(int ...$args): array {
    return $args; // $args is array<array-key, int> since it can have named arguments
}
```

---

### Running Psalm Issues MixedArrayAccess (`docs/running_psalm/issues/MixedArrayAccess.md`)

# MixedArrayAccess

Emitted when trying to access an array offset on a value whose type Psalm cannot determine

```php
<?php

echo $GLOBALS['foo'][0];
```

---

### Running Psalm Issues MixedArrayAssignment (`docs/running_psalm/issues/MixedArrayAssignment.md`)

# MixedArrayAssignment

Emitted when trying to assign a value to an array offset on a value whose type Psalm cannot determine

```php
<?php

$GLOBALS['foo'][0] = "5";
```

---

### Running Psalm Issues MixedArrayOffset (`docs/running_psalm/issues/MixedArrayOffset.md`)

# MixedArrayOffset

Emitted when attempting to access an array offset where Psalm cannot determine the offset type

```php
<?php

echo [1, 2, 3][$GLOBALS['foo']];
```

---

### Running Psalm Issues MixedArrayTypeCoercion (`docs/running_psalm/issues/MixedArrayTypeCoercion.md`)

# MixedArrayTypeCoercion

Emitted when trying to access an array with a less specific offset than is expected

```php
<?php

/**
 * @param array<array-key, int> $a
 * @param array<int, string> $b
 */
function foo(array $a, array $b) : void {
    foreach ($a as $j => $k) {
        echo $b[$j];
    }
}
```

---

### Running Psalm Issues MixedAssignment (`docs/running_psalm/issues/MixedAssignment.md`)

# MixedAssignment

Emitted when assigning an unannotated variable to a value for which Psalm
cannot infer a type more specific than `mixed`.

```php
<?php

$a = $GLOBALS['foo'];
```

## How to fix

The above example can be fixed in a few ways – by adding an `assert` call:

```php
<?php

$a = $GLOBALS['foo'];
assert(is_string($a));
```

or by adding an explicit cast:

```php
<?php

$a = (string) $GLOBALS['foo'];
```

or by adding a docblock

```php
<?php

/** @var string */
$a = $GLOBALS['foo'];
```

---

### Running Psalm Issues MixedClone (`docs/running_psalm/issues/MixedClone.md`)

# MixedClone

Emitted when trying to clone a value whose type is not known

```php
<?php

$a = clone $GLOBALS["a"];
```

---

### Running Psalm Issues MixedFunctionCall (`docs/running_psalm/issues/MixedFunctionCall.md`)

# MixedFunctionCall

Emitted when calling a function on a value whose type Psalm cannot infer.

```php
<?php

/** @var mixed */
$a = $GLOBALS['foo'];
$a();
```

---

### Running Psalm Issues MixedMethodCall (`docs/running_psalm/issues/MixedMethodCall.md`)

# MixedMethodCall

Emitted when calling a method on a value that Psalm cannot infer a type for

```php
<?php

class A {
    public function foo() : void {}
}

function callFoo(array $arr) : void {
    array_pop($arr)->foo(); // MixedMethodCall emitted here
}

callFoo(
    [new A()]
);
```

## Why this is bad

If Psalm does not know what `array_pop($arr)` is, it can't verify whether `array_pop($arr)->foo()` will work or not.

## How to fix

Make sure that to provide as much type information as possible to Psalm so that it can perform inference. For example, you could add a docblock to the `callFoo` function:

```php
<?php

class A {
    public function foo() : void {}
}

/**
 * @param  array<A> $arr
 */
function callFoo(array $arr) : void {
    array_pop($arr)->foo(); // MixedMethodCall emitted here
}

callFoo(
    [new A()]
);
```

Alternatively you could add a runtime check:

```php
<?php

class A {
    public function foo() : void {}
}

function callFoo(array $arr) : void {
    $a = array_pop($arr);
    assert($a instanceof A);
    $a->foo(); // MixedMethodCall emitted here
}

callFoo(
    [new A()]
);
```

---

### Running Psalm Issues MixedOperand (`docs/running_psalm/issues/MixedOperand.md`)

# MixedOperand

Emitted when Psalm cannot infer a type for an operand in any calculated expression

```php
<?php

echo $GLOBALS['foo'] + "hello";
```

## Why it’s bad

Mixed operands can have fatal consequences, e.g. here:

```php
<?php

function foo(mixed $m) {
    echo $m . 'bar';
}

class A {}

foo(new A()); // triggers fatal error
```

---

### Running Psalm Issues MixedPropertyAssignment (`docs/running_psalm/issues/MixedPropertyAssignment.md`)

# MixedPropertyAssignment

Emitted when assigning a property to a value for which Psalm cannot infer a type

```php
<?php

/** @param mixed $a */
function foo($a) : void {
    $a->foo = "bar";
}
```

---

### Running Psalm Issues MixedPropertyFetch (`docs/running_psalm/issues/MixedPropertyFetch.md`)

# MixedPropertyFetch

Emitted when retrieving a property on a value for which Psalm cannot infer a type

```php
<?php

/** @param mixed $a */
function foo($a) : void {
    echo $a->foo;
}
```

---

### Running Psalm Issues MixedPropertyTypeCoercion (`docs/running_psalm/issues/MixedPropertyTypeCoercion.md`)

# MixedPropertyTypeCoercion

Emitted when Psalm cannot be sure that part of an array/iterable argument's type constraints can be fulfilled

```php
<?php

class A {
    /** @var string[] */
    public $takesStringArray = [];
}

function foo(A $a, array $arr) : void {
    $a->takesStringArray = $arr;
}
```

---

### Running Psalm Issues MixedReturnStatement (`docs/running_psalm/issues/MixedReturnStatement.md`)

# MixedReturnStatement

Emitted when Psalm cannot determine the type of a given return statement

```php
<?php

function foo() : int {
    return $GLOBALS['foo']; // emitted here
}
```

---

### Running Psalm Issues MixedReturnTypeCoercion (`docs/running_psalm/issues/MixedReturnTypeCoercion.md`)

# MixedReturnTypeCoercion

Emitted when Psalm cannot be sure that part of an array/iterable return type's constraints can be fulfilled

```php
<?php

/**
 * @return string[]
 */
function foo(array $a) : array {
    return $a;
}
```

This can happen with variadic arguments when `@no-named-arguments` is not specified:

```php
<?php

/** @return list<int> */
function foo(int ...$args): array {
    return $args; // $args is array<array-key, int> since it can have named arguments
}
```

---

### Running Psalm Issues MixedStringOffsetAssignment (`docs/running_psalm/issues/MixedStringOffsetAssignment.md`)

# MixedStringOffsetAssignment

Emitted when assigning a value on a string using a value for which Psalm cannot infer a type

```php
<?php

"hello"[0] = $GLOBALS['foo'];
```

---

### Running Psalm Issues MoreSpecificImplementedParamType (`docs/running_psalm/issues/MoreSpecificImplementedParamType.md`)

# MoreSpecificImplementedParamType

Emitted when a class implements an interface method but a param type is more specific than the interface method param type

```php
<?php

class A {}
class B extends A {
    public function bar(): void {}
}
class C extends A {
    public function bar(): void {}
}

class D {
    public function foo(A $a): void {}
}

class E extends D {
    /** @param B|C $a */
    public function foo(A $a): void {
        $a->bar();
    }
}
```

---

### Running Psalm Issues MoreSpecificReturnType (`docs/running_psalm/issues/MoreSpecificReturnType.md`)

# MoreSpecificReturnType

Emitted when the declared return type for a method is more specific than the inferred one (emitted in the same methods that `LessSpecificReturnStatement` is)

```php
<?php

class A {}
class B extends A {}
function foo() : B {
    /** @psalm-suppress LessSpecificReturnStatement */
    return new A();
}
```

---

### Running Psalm Issues MutableDependency (`docs/running_psalm/issues/MutableDependency.md`)

# MutableDependency

Emitted when an immutable class inherits from a class or trait not marked @psalm-immutable

```php
<?php

class MutableParent {
    public int $i = 0;

    public function increment() : void {
        $this->i++;
    }
}

/**
 * @psalm-immutable
 */
final class NotReallyImmutableClass extends MutableParent {}
```

---

### Running Psalm Issues NamedArgumentNotAllowed (`docs/running_psalm/issues/NamedArgumentNotAllowed.md`)

# NamedArgumentNotAllowed

Emitted when a named argument is used when calling a function with `@no-named-arguments`.

```php
<?php

/** @no-named-arguments */
function foo(int $a, int $b): int {
	return $a + $b;
}

foo(a: 0, b: 1);

```

## Why this is bad

The `@no-named-arguments` annotation indicates that argument names may be changed in the future, and an update may break backwards compatibility with function calls using named arguments.

## How to fix

Avoid using named arguments for functions annotated with `@no-named-arguments`.

```php
<?php

/** @no-named-arguments */
function foo(int $a, int $b): int {
	return $a + $b;
}

foo(0, 1);

```

---

### Running Psalm Issues NoEnumProperties (`docs/running_psalm/issues/NoEnumProperties.md`)

# NoEnumProperties

Emitted when there a property defined on an enum, as PHP
does not allow user-defined properties on enums.

```php
<?php

enum Status {
    public $prop;
}
```

---

### Running Psalm Issues NoInterfaceProperties (`docs/running_psalm/issues/NoInterfaceProperties.md`)

# NoInterfaceProperties

Emitted when trying to fetch a property on an interface as interfaces, by definition, do not have definitions for properties.

```php
<?php

interface I {}
class A implements I {
    /** @var ?string */
    public $foo;
}
function bar(I $i) : void {
    if ($i->foo) {}
}
```

---

### Running Psalm Issues NoValue (`docs/running_psalm/issues/NoValue.md`)

# NoValue

Emitted when Psalm invalidated all possible types for a given expression. It is often an indication that Psalm found dead code or that documented types were not exhaustive

```php
<?php

/**
 * @return never
 */
function foo() : void {
    exit();
}

$a = foo(); // Psalm knows $a will never contain any type because foo() won't return
```

```php
<?php

function foo() : void {
    return throw new Exception(''); //Psalm detected the return expression is never used
}
```

```php
<?php
function shutdown(): never {die('Application closed unexpectedly');}
function foo(string $_a): void{}

foo(shutdown()); // foo() will never be called
```

```php
<?php
$a = [];
/** @psalm-suppress TypeDoesNotContainType */
assert(!empty($a));

count($a); // Assert above always fail. There is no possible type that $a can have here
```

---

### Running Psalm Issues NonInvariantDocblockPropertyType (`docs/running_psalm/issues/NonInvariantDocblockPropertyType.md`)

# NonInvariantDocblockPropertyType

Emitted when a public or protected class property has a different docblock type to the matching property in the parent class.

```php
<?php

class A {
    /** @var null|string */
    public $foo = 'hello';
}

class AChild extends A {
    /** @var string */
    public $foo;
}
```

## Why this is bad

For non-typed properties, it can cause a type system violation when code written against the parent class reads or writes a value on an object of the child class.

If the child class widens the type then reading the value may return unexpected value that client code cannot deal with. If the child class narrows the type then code setting the value may set it to an invalid value:

```php
<?php

function takesA(A $a) {
    $a->foo = null; // this is valid for A
}

$child = new AChild();
takesA($child);
echo strlen($child->foo); // this is valid for AChild
```

## Workarounds

You can either broaden the type or you could, in certain situations, use templates instead:

```php
<?php

/**
 * @template T of string|null
 */
abstract class A {
    /** @var T */
    public $foo = 'hello';
}

/**
 * @extends A<string>
 */
class AChild extends A {
    /** @var string */
    public $foo;
}
```

---

### Running Psalm Issues NonInvariantPropertyType (`docs/running_psalm/issues/NonInvariantPropertyType.md`)

# NonInvariantPropertyType

Emitted when a public or protected class property has a different type to the matching property in the parent class.

```php
<?php

class A {
    public string $foo = 'hello';
}

class B extends A {
    public ?string $foo;
}

```

## Why this is bad

For typed properties, this can cause a compile error.

---

### Running Psalm Issues NonStaticSelfCall (`docs/running_psalm/issues/NonStaticSelfCall.md`)

# NonStaticSelfCall

Emitted when calling a non-static function statically

```php
<?php

class A {
    public function foo(): void {}

    public static function bar(): void {
        self::foo();
    }
}
```

---

### Running Psalm Issues NonVariableReferenceReturn (`docs/running_psalm/issues/NonVariableReferenceReturn.md`)

# NonVariableReferenceReturn

Emitted when a function returns by reference expression that is not a variable

```php
<?php

function &getByRef(): int {
    return 5;
}
```

---

### Running Psalm Issues NullArgument (`docs/running_psalm/issues/NullArgument.md`)

# NullArgument

Emitted when calling a function with a null value argument when the function does not expect it

```php
<?php

function foo(string $s) : void {}
foo(null);
```

---

### Running Psalm Issues NullArrayAccess (`docs/running_psalm/issues/NullArrayAccess.md`)

# NullArrayAccess

Emitted when trying to access an array value on `null`

```php
<?php

$arr = null;
echo $arr[0];
```

---

### Running Psalm Issues NullArrayOffset (`docs/running_psalm/issues/NullArrayOffset.md`)

# NullArrayOffset

Emitted when trying to access an array offset with `null`

```php
<?php

$arr = ['' => 5, 'foo' => 1];
echo $arr[null];
```

---

### Running Psalm Issues NullFunctionCall (`docs/running_psalm/issues/NullFunctionCall.md`)

# NullFunctionCall

Emitted when trying to use `null` as a `callable`

```php
<?php

$arr = null;
echo $arr();
```

---

### Running Psalm Issues NullIterator (`docs/running_psalm/issues/NullIterator.md`)

# NullIterator

Emitted when iterating over `null`

```php
<?php

foreach (null as $a) {}
```

---

### Running Psalm Issues NullOperand (`docs/running_psalm/issues/NullOperand.md`)

# NullOperand

Emitted when using `null` as part of an operation (e.g. `+`, `.`, `^` etc.)

```php
<?php

echo null . 'hello';
```

---

### Running Psalm Issues NullPropertyAssignment (`docs/running_psalm/issues/NullPropertyAssignment.md`)

# NullPropertyAssignment

Emitted when trying to set a property on `null`

```php
<?php

$a = null;
$a->foo = "bar";
```

---

### Running Psalm Issues NullPropertyFetch (`docs/running_psalm/issues/NullPropertyFetch.md`)

# NullPropertyFetch

Emitted when trying to fetch a property on a `null` value

```php
<?php

$a = null;
echo $a->foo;
```

---

### Running Psalm Issues NullReference (`docs/running_psalm/issues/NullReference.md`)

# NullReference

Emitted when attempting to call a method on `null`

```php
<?php

$a = null;
$a->foo();
```

---

### Running Psalm Issues NullableReturnStatement (`docs/running_psalm/issues/NullableReturnStatement.md`)

# NullableReturnStatement

Emitted if a return statement contains a null value, but the function return type is not nullable

```php
<?php

function foo() : string {
    if (rand(0, 1)) {
        return "foo";
    }

    return null; // emitted here
}
```

---

### Running Psalm Issues OverriddenFinalConstant (`docs/running_psalm/issues/OverriddenFinalConstant.md`)

# OverriddenFinalConstant

Emitted when a constant declared as final is overridden in a child class or interface.

```php
<?php

class Foo
{
    /** @var string */
    final public const BAR='baz';
}

class Bar extends Foo
{
    /** @var string */
    public const BAR='foobar';
}
```

---

### Running Psalm Issues OverriddenFinalProperty (`docs/running_psalm/issues/OverriddenFinalProperty.md`)

# OverriddenFinalProperty

Emitted when a property declared as final is redeclared in a child class. Properties declared with `private(set)`
asymmetric visibility are implicitly final.

```php
<?php

class Foo
{
    public private(set) string $bar = 'baz';
}

class Bar extends Foo
{
    public string $bar = 'foobar';
}
```

---

### Running Psalm Issues OverriddenInterfaceConstant (`docs/running_psalm/issues/OverriddenInterfaceConstant.md`)

# OverriddenInterfaceConstant

Emitted when a constant declared on an interface is overridden by a child (illegal in PHP < 8.1).

```php
<?php

interface Foo
{
    public const BAR='baz';
}

interface Bar extends Foo
{
    public const BAR='foobar';
}
```

---

### Running Psalm Issues OverriddenMethodAccess (`docs/running_psalm/issues/OverriddenMethodAccess.md`)

# OverriddenMethodAccess

Emitted when a method is less accessible than its parent

```php
<?php

class A {
    public function foo() : void {}
}
class B extends A {
    protected function foo() : void {}
}
```

---

### Running Psalm Issues OverriddenPropertyAccess (`docs/running_psalm/issues/OverriddenPropertyAccess.md`)

# OverriddenPropertyAccess

Emitted when a property is less accessible than the same-named property in its parent class

```php
<?php

class A {
    /** @var string|null */
    public $foo;
}
class B extends A {
    /** @var string|null */
    protected $foo;
}
```

---

### Running Psalm Issues ParadoxicalCondition (`docs/running_psalm/issues/ParadoxicalCondition.md`)

# ParadoxicalCondition

Emitted when a paradox is encountered in your programs logic that could not be caught by `RedundantCondition`

```php
<?php

function foo(string $input) : string {
    return $input === "a" ? "bar" : ($input === "a" ? "foo" : "b");
}
```

---

### Running Psalm Issues ParamNameMismatch (`docs/running_psalm/issues/ParamNameMismatch.md`)

# ParamNameMismatch

Emitted when method overrides a parent method but renames a param.

```php
<?php

class A {
    public function foo(string $str, bool $b = false) : void {}
}

class AChild extends A {
    public function foo(string $string, bool $b = false) : void {}
}
```

## Why is this bad?

PHP 8 introduces [named parameters](https://wiki.php.net/rfc/named_params) which allow developers to call methods with explicitly-named parameters;

```php
<?php

function callFoo(A $a) {
    $a->foo(str: "hello");
}
```

In the first example passing `new AChild()` to `callFoo()` results in a fatal error, as AChild's definition of the method `foo()` doesn't have a parameter named `$str`.

## How to fix

You can change the child method param name to match:

```php
<?php

class A {
    public function foo(string $str, bool $b = false) : void {}
}

class AChild extends A {
    public function foo(string $str, bool $b = false) : void {}
}
```

This fix [can be applied automatically by Psalter](https://psalm.dev/docs/manipulating_code/fixing/#paramnamemismatch).

## Workarounds

### @no-named-arguments

Alternatively you can ignore this issue by adding a `@no-named-arguments` annotation to the parent method:

```php
<?php

class A {
    /** @no-named-arguments */
    public function foo(string $str, bool $b = false) : void {}
}

class AChild extends A {
    public function foo(string $string, bool $b = false) : void {}
}
```

Any method with this annotation will be prevented (by Psalm) from being called with named parameters, so the original issue does not matter.

### Config allowNamedArgumentCalls="false"

This prevents any use of named params in your codebase. Ideal for self-contained projects, but less ideal for libraries.

It means the original code above will not emit any errors as long as the class `A` is defined in a directory that Psalm can scan.

### Config allowInternalNamedArgumentCalls="false"

For library authors Psalm supports a more nuanced flag that tells Psalm to prohibit any named parameter calls on `@internal` classes or methods.

With that config value, this is now allowed:

```php
<?php

/**
 * @internal
 */
class A {
    public function foo(string $str, bool $b = false) : void {}
}

class AChild extends A {
    public function foo(string $string, bool $b = false) : void {}
}
```

---

### Running Psalm Issues ParentNotFound (`docs/running_psalm/issues/ParentNotFound.md`)

# ParentNotFound

Emitted when using `parent::` in a class without a parent class.

```php
<?php

class A {
  public function foo() : void {
    parent::foo();
  }
}
```

---

### Running Psalm Issues ParseError (`docs/running_psalm/issues/ParseError.md`)

# ParseError

Emitted when the PHP Parser encounters an error.

```php
<?php

class A {
  public function foo() : void {
    echo "foo"
  }
}
```

---

### Running Psalm Issues PossibleRawObjectIteration (`docs/running_psalm/issues/PossibleRawObjectIteration.md`)

# PossibleRawObjectIteration

Emitted when possibly iterating over an object’s properties, the comparison to [RawObjectIteration](#rawobjectiteration).

```php
<?php

class A {
    /** @var string|null */
    public $foo;

    /** @var string|null */
    public $bar;
}

function takesA(A $a) {
    if (rand(0, 1)) {
        $a = [1, 2, 3];
    }

    foreach ($a as $property) {}
}
```

---

### Running Psalm Issues PossiblyFalseArgument (`docs/running_psalm/issues/PossiblyFalseArgument.md`)

# PossiblyFalseArgument

Emitted when a function argument is possibly `false`, but the function does not expect `false`. This is distinct from a function argument is possibly `bool`, which results in `PossiblyInvalidArgument`.

```php
<?php

function foo(string $s) : void {
    $a_pos = strpos($s, "a");
    echo substr($s, $a_pos);
}
```

---

### Running Psalm Issues PossiblyFalseIterator (`docs/running_psalm/issues/PossiblyFalseIterator.md`)

# PossiblyFalseIterator

Emitted when trying to iterate over a value that may be `false`

```php
<?php

$arr = rand(0, 1) ? [1, 2, 3] : false;
foreach ($arr as $a) {}
```

---

### Running Psalm Issues PossiblyFalseOperand (`docs/running_psalm/issues/PossiblyFalseOperand.md`)

# PossiblyFalseOperand

Emitted when using a possibly `false` value as part of an operation (e.g. `+`, `.`, `^` etc).

```php
<?php

function echoCommaPosition(string $str) : void {
    echo 'The comma is located at ' . strpos($str, ','); 
}
```

## How to fix

You can detect the `false` value with some extra logic:

```php
<?php

function echoCommaPosition(string $str) : void {
    $pos = strpos($str, ',');

    if ($pos === false) {
        echo 'There is no comma in the string';
    }

    echo 'The comma is located at ' . $pos; 
}
```

Alternatively you can just use a ternary to suppress this issue:

```php
<?php

function echoCommaPosition(string $str) : void {
    echo 'The comma is located at ' . (strpos($str, ',') ?: ''); 
}
```

---

### Running Psalm Issues PossiblyFalsePropertyAssignmentValue (`docs/running_psalm/issues/PossiblyFalsePropertyAssignmentValue.md`)

# PossiblyFalsePropertyAssignmentValue

Emitted when trying to assign a value that may be false to a property that only takes non-false values.

```php
<?php

class A {
    /** @var int */
    public $foo = 0;
}

function assignToA(string $s) {
    $a = new A();
    $a->foo = strpos($s, "haystack");
}
```

---

### Running Psalm Issues PossiblyFalseReference (`docs/running_psalm/issues/PossiblyFalseReference.md`)

# PossiblyFalseReference

Emitted when making a method call on a value that might be `false`

```php
<?php

class A {
    public function bar() : void {}
}

/** @return A|false */
function foo() {
    return rand(0, 1) ? new A : false;
}

foo()->bar();
```

---

### Running Psalm Issues PossiblyInvalidArgument (`docs/running_psalm/issues/PossiblyInvalidArgument.md`)

# PossiblyInvalidArgument

Emitted when

```php
<?php

/** @return int|stdClass */
function foo() {
    return rand(0, 1) ? 5 : new stdClass;
}
function bar(int $i) : void {}
bar(foo());
```

---

### Running Psalm Issues PossiblyInvalidArrayAccess (`docs/running_psalm/issues/PossiblyInvalidArrayAccess.md`)

# PossiblyInvalidArrayAccess

Emitted when attempting to access an array offset on a value that may not be an array

```php
<?php

$arr = rand(0, 1) ? 5 : [4, 3, 2, 1];
echo $arr[0];
```

---

### Running Psalm Issues PossiblyInvalidArrayAssignment (`docs/running_psalm/issues/PossiblyInvalidArrayAssignment.md`)

# PossiblyInvalidArrayAssignment

Emitted when attempting to assign an array offset on a value that may not be an array

```php
<?php

$arr = rand(0, 1) ? 5 : [4, 3, 2, 1];
$arr[0] = "hello";
```

---

### Running Psalm Issues PossiblyInvalidArrayOffset (`docs/running_psalm/issues/PossiblyInvalidArrayOffset.md`)

# PossiblyInvalidArrayOffset

Emitted when it’s possible that the array offset is not applicable to the value you’re trying to access.

```php
<?php

$arr = rand(0, 1) ? ["a" => 5] : "hello";
echo $arr[0];
```

---

### Running Psalm Issues PossiblyInvalidCast (`docs/running_psalm/issues/PossiblyInvalidCast.md`)

# PossiblyInvalidCast

Emitted when attempting to cast a value that may not be castable

```php
<?php

class A {}
class B {
    public function __toString() {
        return 'hello';
    }
}
$c = (string) (rand(0, 1) ? new A() : new B());
```

---

### Running Psalm Issues PossiblyInvalidClone (`docs/running_psalm/issues/PossiblyInvalidClone.md`)

# PossiblyInvalidClone

Emitted when trying to clone a value that's possibly not cloneable

```php
<?php

class A {}

/**
 * @param A|string $a
 */
function foo($a) {
    return clone $a;
}
```

---

### Running Psalm Issues PossiblyInvalidDocblockTag (`docs/running_psalm/issues/PossiblyInvalidDocblockTag.md`)

# PossiblyInvalidDocblockTag

Emitted when Psalm detects a likely mix-up of docblock tags, e.g. `@var`
used on a method (where `@param` is likely expected).

```php
<?php

/** @var int $param */
function foo($param): void {}
```

---

### Running Psalm Issues PossiblyInvalidFunctionCall (`docs/running_psalm/issues/PossiblyInvalidFunctionCall.md`)

# PossiblyInvalidFunctionCall

Emitted when trying to call a function on a value that may not be callable

```php
<?php

$a = rand(0, 1) ? 5 : function() : int { return 5; };
$b = $a();
```

---

### Running Psalm Issues PossiblyInvalidIterator (`docs/running_psalm/issues/PossiblyInvalidIterator.md`)

# PossiblyInvalidIterator

Emitted when trying to iterate over a value that may be invalid

```php
<?php

$arr = rand(0, 1) ? [1, 2, 3] : "hello";
foreach ($arr as $a) {}
```

---

### Running Psalm Issues PossiblyInvalidMethodCall (`docs/running_psalm/issues/PossiblyInvalidMethodCall.md`)

# PossiblyInvalidMethodCall

Emitted when trying to call a method on a value that may not be an object

```php
<?php

class A {
    public function bar() : void {}
}

/** @return A|int */
function foo() {
    return rand(0, 1) ? new A : 5;
}

foo()->bar();
```

---

### Running Psalm Issues PossiblyInvalidOperand (`docs/running_psalm/issues/PossiblyInvalidOperand.md`)

# PossiblyInvalidOperand

Emitted when using a possibly invalid value as part of an operation (e.g. `+`, `.`, `^` etc.

```php
<?php

function foo() : void {
    $b = rand(0, 1) ? [] : 4;
    echo $b + 5;
}
```

---

### Running Psalm Issues PossiblyInvalidPropertyAssignment (`docs/running_psalm/issues/PossiblyInvalidPropertyAssignment.md`)

# PossiblyInvalidPropertyAssignment

Emitted when trying to assign a property on a value that may not be an object or may be an object that does not have the desired property.

```php
<?php

class A {
    /** @var ?string */
    public $bar;
}

/** @return A|int */
function foo() {
    return rand(0, 1) ? new A : 5;
}

$a = foo();
$a->bar = "5";
```

---

### Running Psalm Issues PossiblyInvalidPropertyAssignmentValue (`docs/running_psalm/issues/PossiblyInvalidPropertyAssignmentValue.md`)

# PossiblyInvalidPropertyAssignmentValue

Emitted when trying to assign a possibly invalid value to a typed property.

```php
<?php

class A {
    /** @var int[] */
    public $bb = [];
}

class B {
    /** @var string[] */
    public $bb;
}

$c = rand(0, 1) ? new A : new B;
$c->bb = ["hello", "world"];
```

---

### Running Psalm Issues PossiblyInvalidPropertyFetch (`docs/running_psalm/issues/PossiblyInvalidPropertyFetch.md`)

# PossiblyInvalidPropertyFetch

Emitted when trying to fetch a property on a value that may not be an object or may be an object that does not have the desired property.

```php
<?php

class A {
    /** @var ?string */
    public $bar;
}

/** @return A|int */
function foo() {
    return rand(0, 1) ? new A : 5;
}

$a = foo();
echo $a->bar;
```

---

### Running Psalm Issues PossiblyNullArgument (`docs/running_psalm/issues/PossiblyNullArgument.md`)

# PossiblyNullArgument

Emitted when calling a function with a value that’s possibly null when the function does not expect it

```php
<?php

function foo(string $s): void {}
foo(rand(0, 1) ? "hello" : null);
```

## Common Problem Cases

### Using a Function Call inside `if`

```php
<?php

if (is_string($cat->getName()) {
    foo($cat->getName());
}
```
This fails since it's not guaranteed that subsequent calls to `$cat->getName()` always give the same result.

#### Possible Solutions

Use a variable:
```php
<?php

$catName = $cat->getName();
if (is_string($catName) {
    foo($catName);
}
unset($catName);
```

Or add [`@psalm-capabilities read-props`](../../annotating_code/supported_annotations.md#psalm-capabilities) to the declaration of the function

### Calling Another Function After `if`

```php
<?php

if (is_string($cat->getName()) {
    changeCat();
    foo($cat->getName());
}
```
This fails since psalm cannot know if `changeCat()` does actually modify `$cat`.

#### Possible Solutions

* Add [`@psalm-capabilities read-props`](../../annotating_code/supported_annotations.md#psalm-capabilities) to the declaration of the other function (here: `changeCat()`) too
* Use a variable: See above

---

### Running Psalm Issues PossiblyNullArrayAccess (`docs/running_psalm/issues/PossiblyNullArrayAccess.md`)

# PossiblyNullArrayAccess

Emitted when trying to access an array offset on a possibly null value

```php
<?php

function foo(?array $a) : void {
    echo $a[0];
}
```

---

### Running Psalm Issues PossiblyNullArrayAssignment (`docs/running_psalm/issues/PossiblyNullArrayAssignment.md`)

# PossiblyNullArrayAssignment

Emitted when trying to set a value on a possibly null array

```php
<?php

$a = null;
$a[0][] = 1;
```

---

### Running Psalm Issues PossiblyNullArrayOffset (`docs/running_psalm/issues/PossiblyNullArrayOffset.md`)

# PossiblyNullArrayOffset

Emitted when trying to access a value on an array using a possibly null offset

```php
<?php

function foo(?int $a) : void {
    echo [1, 2, 3, 4][$a];
}
```

---

### Running Psalm Issues PossiblyNullFunctionCall (`docs/running_psalm/issues/PossiblyNullFunctionCall.md`)

# PossiblyNullFunctionCall

Emitted when trying to call a function on a value that may be null

```php
<?php

function foo(?callable $a) : void {
    $a();
}
```

---

### Running Psalm Issues PossiblyNullIterator (`docs/running_psalm/issues/PossiblyNullIterator.md`)

# PossiblyNullIterator

Emitted when trying to iterate over a value that may be null

```php
<?php

function foo(?array $arr) : void {
    foreach ($arr as $a) {}
}
```

---

### Running Psalm Issues PossiblyNullOperand (`docs/running_psalm/issues/PossiblyNullOperand.md`)

# PossiblyNullOperand

Emitted when using a possibly `null` value as part of an operation (e.g. `+`, `.`, `^` etc.)

```php
<?php

function foo(?int $a) : void {
    echo $a + 5;
}
```

---

### Running Psalm Issues PossiblyNullPropertyAssignment (`docs/running_psalm/issues/PossiblyNullPropertyAssignment.md`)

# PossiblyNullPropertyAssignment

Emitted when trying to assign a property to a possibly null object

```php
<?php

class A {
    /** @var ?string */
    public $foo;
}
function foo(?A $a) : void {
    $a->foo = "bar";
}
```

---

### Running Psalm Issues PossiblyNullPropertyAssignmentValue (`docs/running_psalm/issues/PossiblyNullPropertyAssignmentValue.md`)

# PossiblyNullPropertyAssignmentValue

Emitted when trying to assign a value that may be null to a property that only takes non-null values.

```php
<?php

class A {
    /** @var string */
    public $foo = "bar";
}

function assignToA(?string $s) {
    $a = new A();
    $a->foo = $s;
}
```

---

### Running Psalm Issues PossiblyNullPropertyFetch (`docs/running_psalm/issues/PossiblyNullPropertyFetch.md`)

# PossiblyNullPropertyFetch

Emitted when trying to fetch a property on a possibly null object

```php
<?php

class A {
    /** @var ?string */
    public $foo;
}
function foo(?A $a) : void {
    echo $a->foo;
}
```

---

### Running Psalm Issues PossiblyNullReference (`docs/running_psalm/issues/PossiblyNullReference.md`)

# PossiblyNullReference

Emitted when trying to call a method on a possibly null value

```php
<?php

class A {
    public function bar() : void {}
}
function foo(?A $a) : void {
    $a->bar();
}
```

---

### Running Psalm Issues PossiblyUndefinedArrayOffset (`docs/running_psalm/issues/PossiblyUndefinedArrayOffset.md`)

# PossiblyUndefinedArrayOffset

Emitted when trying to access a possibly undefined array offset

```php
<?php

if (rand(0, 1)) {
    $arr = ["a" => 1, "b" => 2];
} else {
    $arr = ["a" => 3];
}

echo $arr["b"];
```

## How to fix

You can use the null coalesce operator to provide a default value in the event the array offset does not exist:

```php
<?php

...

echo $arr["b"] ?? 0;
```

Alternatively, you can ensure that the array offset always exists:

```php
<?php

if (rand(0, 1)) {
    $arr = ["a" => 1, "b" => 2];
} else {
    $arr = ["a" => 3, "b" => 0];
}

echo $arr["b"];
```

---

### Running Psalm Issues PossiblyUndefinedGlobalVariable (`docs/running_psalm/issues/PossiblyUndefinedGlobalVariable.md`)

# PossiblyUndefinedGlobalVariable

Emitted when trying to access a variable in the global scope that may not be defined

```php
<?php

if (rand(0, 1)) {
  $a = 5;
}
echo $a;
```

---

### Running Psalm Issues PossiblyUndefinedIntArrayOffset (`docs/running_psalm/issues/PossiblyUndefinedIntArrayOffset.md`)

# PossiblyUndefinedIntArrayOffset

Emitted when the config flag `ensureArrayIntOffsetsExist` is set to `true` and an integer-keyed offset is not checked for existence

```php
<?php

/**
 * @param array<int, string> $arr
 */
function foo(array $arr) : void {
    echo $arr[0];
}
```

---

### Running Psalm Issues PossiblyUndefinedMethod (`docs/running_psalm/issues/PossiblyUndefinedMethod.md`)

# PossiblyUndefinedMethod

Emitted when trying to access a method that may not be defined on the object

```php
<?php

class A {
    public function bar() : void {}
}
class B {}

$a = rand(0, 1) ? new A : new B;
$a->bar();
```

---

### Running Psalm Issues PossiblyUndefinedStringArrayOffset (`docs/running_psalm/issues/PossiblyUndefinedStringArrayOffset.md`)

# PossiblyUndefinedStringArrayOffset

Emitted when the config flag `ensureArrayStringOffsetsExist` is set to `true` and a string-keyed offset is not checked for existence

```php
<?php

/**
 * @param array<string, string> $arr
 */
function foo(array $arr) : void {
    echo $arr["hello"];
}
```

---

### Running Psalm Issues PossiblyUndefinedVariable (`docs/running_psalm/issues/PossiblyUndefinedVariable.md`)

# PossiblyUndefinedVariable

Emitted when trying to access a variable in function scope that may not be defined

```php
<?php

function foo() : void {
    if (rand(0, 1)) {
        $a = 5;
    }
    echo $a;
}
```

---

### Running Psalm Issues PossiblyUnusedMethod (`docs/running_psalm/issues/PossiblyUnusedMethod.md`)

# PossiblyUnusedMethod

Emitted when `--find-dead-code` is turned on and Psalm cannot find any calls to
a public or protected method.

If this method is genuinely part of your public API — used from outside the analysed codebase (for example a library entry point, or a method invoked only by a framework) — annotate the containing class with `@api` (or `@psalm-api`) — mark the whole class rather than the individual method, since a public-API method almost always belongs to a public-API class. Otherwise the method is dead code and should be removed: a method reported as unused in a class that is **not** already marked `@api` is almost always genuinely unused, so annotating the individual method with `@api` to silence the report is very rarely the right fix.

See [`@api`](../../annotating_code/supported_annotations.md#api-psalm-api) for the full guidance; note that `@psalm-suppress` is not a substitute for `@api`, as it silences the report without marking the method as used.

```php
<?php

class A {
    public function foo() : void {}
    public function bar() : void {}
}
(new A)->foo();
```

---

### Running Psalm Issues PossiblyUnusedParam (`docs/running_psalm/issues/PossiblyUnusedParam.md`)

# PossiblyUnusedParam

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a particular parameter in a public/protected method

```php
<?php

class A {
    public function foo(int $a, int $b) : int {
        return $a + 4;
    }
}

$a = new A();
echo $a->foo(1, 2);
```

Can be suppressed by prefixing the parameter name with an underscore:

```php
<?php
class A {
    public function foo(int $a, int $_b) : int {
        return $a + 4;
    }
}
```

---

### Running Psalm Issues PossiblyUnusedProperty (`docs/running_psalm/issues/PossiblyUnusedProperty.md`)

# PossiblyUnusedProperty

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a
particular public/protected property.

If this property is genuinely part of your public API — used from outside the analysed codebase (for example a library entry point, or a property accessed only by a framework) — annotate the containing class with `@api` (or `@psalm-api`) — mark the whole class rather than the individual property, since a public-API property almost always belongs to a public-API class. Otherwise the property is dead code and should be removed: a property reported as unused in a class that is **not** already marked `@api` is almost always genuinely unused, so annotating the individual property with `@api` to silence the report is very rarely the right fix.

See [`@api`](../../annotating_code/supported_annotations.md#api-psalm-api) for the full guidance; note that `@psalm-suppress` is not a substitute for `@api`, as it silences the report without marking the property as used.

```php
<?php

class A {
    /** @var string|null */
    public $foo;

    /** @var int|null */
    public $bar;
}

$a = new A();
echo $a->foo;
```

---

### Running Psalm Issues PossiblyUnusedReturnValue (`docs/running_psalm/issues/PossiblyUnusedReturnValue.md`)

# PossiblyUnusedReturnValue

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a public/protected method’s return type.

```php
<?php

class A {
    public function foo() : string {
        return "hello";
    }
}
(new A)->foo();
```

---

### Running Psalm Issues PrivateFinalMethod (`docs/running_psalm/issues/PrivateFinalMethod.md`)

# PrivateFinalMethod

Emitted when a class defines private final method. PHP 8.0+ emits a warning when it sees private final method (except `__construct` where it's allowed), and allows redefinition in child classes (effectively ignoring `final` modifier). Before PHP 8.0, `final` was respected in this case.

```php
<?php
class Foo {
    final private function baz(): void {}
}
```

## Why this is bad

It causes a warning, and behavior differs between versions.

---

### Running Psalm Issues PropertyNotSetInConstructor (`docs/running_psalm/issues/PropertyNotSetInConstructor.md`)

# PropertyNotSetInConstructor

Uninitialized properties are hard to statically analyze. To prevent mistakes, Psalm will enforce that all properties should be initialized.

It does that through [MissingConstructor](./MissingConstructor.md) and this issue.

Psalm will then assume every property in the codebase is initialized.

Doing that allows it to report missing initializations as well as [RedundantPropertyInitializationCheck](./RedundantPropertyInitializationCheck.md)

This issue is emitted when a non-null property without a default value is declared but not set in the class’s constructor

If your project relies on having uninitialized properties, it is advised to suppress this issue, as well as [MissingConstructor](./MissingConstructor.md) and [RedundantPropertyInitializationCheck](./RedundantPropertyInitializationCheck.md).

```php
<?php

class A {
    /** @var string */
    public $foo;

    public function __construct() {}
}
```

---

### Running Psalm Issues PropertyTypeCoercion (`docs/running_psalm/issues/PropertyTypeCoercion.md`)

# PropertyTypeCoercion

Emitted when setting a property with a value which has a less specific type than the property expects

```php
<?php

class A {}
class B extends A {}

function takesA(C $c, A $a) : void {
    $c->b = $a;
}

class C {
    /** @var ?B */
    public $b;
}
```

---

### Running Psalm Issues RawObjectIteration (`docs/running_psalm/issues/RawObjectIteration.md`)

# RawObjectIteration

Emitted when iterating over an object’s properties. This issue exists because it may be undesired behaviour (e.g. you may have meant to iterate over an array)

```php
<?php

class A {
    /** @var string|null */
    public $foo;

    /** @var string|null */
    public $bar;
}

function takesA(A $a) {
    foreach ($a as $property) {}
}
```

---

### Running Psalm Issues RedundantCast (`docs/running_psalm/issues/RedundantCast.md`)

# RedundantCast

Emitted when a cast (string, int, float etc.) is redundant

```php
<?php
function foo(string $s) : string {
    return (string) $s;
}
```

---

### Running Psalm Issues RedundantCastGivenDocblockType (`docs/running_psalm/issues/RedundantCastGivenDocblockType.md`)

# RedundantCastGivenDocblockType

Emitted when a cast (string, int, float etc.) is redundant given the docblock-provided type

```php
<?php
/**
 * @param  string $s
 */
function foo($s) : string {
    return (string) $s;
}
```

---

### Running Psalm Issues RedundantCondition (`docs/running_psalm/issues/RedundantCondition.md`)

# RedundantCondition

Emitted when conditional is redundant given previous assertions

```php
<?php

class A {}
function foo(A $a) : ?A {
    if ($a) return $a;
    return null;
}
```

---

### Running Psalm Issues RedundantConditionGivenDocblockType (`docs/running_psalm/issues/RedundantConditionGivenDocblockType.md`)

# RedundantConditionGivenDocblockType

Emitted when conditional is redundant given information supplied in one or more docblocks.

This may be desired (e.g. when checking user input) so is distinct from RedundantCondition, which only applies to non-docblock types.

```php
<?php

/**
 * @param string $s
 *
 * @return void
 */
function foo($s) {
    if (is_string($s)) {};
}
```

---

### Running Psalm Issues RedundantFlag (`docs/running_psalm/issues/RedundantFlag.md`)

# RedundantFlag

Emitted when a flag is redundant. e.g. FILTER_NULL_ON_FAILURE won't do anything when the default option is specified

```php
<?php
$x = filter_input(INPUT_GET, 'hello', FILTER_VALIDATE_DOMAIN, array('options' => array('default' => 'world.com'), 'flags' => FILTER_NULL_ON_FAILURE));
```

---

### Running Psalm Issues RedundantFunctionCall (`docs/running_psalm/issues/RedundantFunctionCall.md`)

# RedundantFunctionCall

Emitted when a function call (`array_values`, `strtolower`, `ksort` etc.) is redundant.

```php
<?php

$a = ['already', 'a', 'list'];

$redundant = array_values($a);
$alreadyLower = strtolower($redundant[0]);
```

---

### Running Psalm Issues RedundantFunctionCallGivenDocblockType (`docs/running_psalm/issues/RedundantFunctionCallGivenDocblockType.md`)

# RedundantFunctionCallGivenDocblockType

Emitted when function call is redundant given information supplied in one or more docblocks.

This may be desired (e.g. when checking user input) so is distinct from RedundantFunctionCall, which only applies to non-docblock types.

```php
<?php

/**
 * @param array{0: lowercase-string, 1: non-empty-list<lowercase-string>} $s
 *
 * @return lowercase-string
 */
function foo($s): string {
    $redundantList = array_values($s);
    $redundantSubList = array_values($s[1]);
    $redundantLowercase = strtolower($redundantSubList[0]);
    return $redundantLowercase;
}
```

---

### Running Psalm Issues RedundantIdentityWithTrue (`docs/running_psalm/issues/RedundantIdentityWithTrue.md`)

# RedundantIdentityWithTrue

This is a codestyle rule, it does not indicate a possible bug.  

Emitted when comparing a known boolean with with a literal boolean and the `allowBoolToLiteralBoolComparison` flag is set to false.

```php
<?php

function returnsABool(): bool {
    return rand(1, 2) === 1;
}

if (returnsABool() === true) {
    echo "hi!";
}

if (returnsABool() !== false) {
    echo "hi!";
}
```

To fix:

```php
<?php

function returnsABool(): bool {
    return rand(1, 2) === 1;
}

if (returnsABool()) {
    echo "hi!";
}

if (returnsABool()) {
    echo "hi!";
}
```

---

### Running Psalm Issues RedundantPropertyInitializationCheck (`docs/running_psalm/issues/RedundantPropertyInitializationCheck.md`)

# RedundantPropertyInitializationCheck

Uninitialized properties are hard to statically analyze. To prevent mistakes, Psalm will enforce that all properties should be initialized.

It does that through [PropertyNotSetInConstructor](./PropertyNotSetInConstructor.md) and [MissingConstructor](./MissingConstructor.md).

Psalm will then assume every property in the codebase is initialized.

Doing that allows it to report missing initializations as well as this issue.

This issue is emitted when checking `isset()` on a non-nullable property. Because every property is assumed to be initialized, this check is redundant

If your project relies on having uninitialized properties, it is advised to suppress this issue, as well as [PropertyNotSetInConstructor](./PropertyNotSetInConstructor.md) and [MissingConstructor](./MissingConstructor.md).

```php
<?php
    class A {
        public string $bar;
        public function getBar() : string {
            if (isset($this->bar)) {
                return $this->bar;
            }
            return "hello";
        }
    }
```

---

### Running Psalm Issues ReferenceConstraintViolation (`docs/running_psalm/issues/ReferenceConstraintViolation.md`)

# ReferenceConstraintViolation

Emitted when changing the type of a pass-by-reference variable

```php
<?php

function foo(string &$a) {
    $a = 5;
}
```

---

### Running Psalm Issues ReferenceReusedFromConfusingScope (`docs/running_psalm/issues/ReferenceReusedFromConfusingScope.md`)

# ReferenceReusedFromConfusingScope

Emitted when a reference assigned in a potentially confusing scope is reused later.
Since PHP doesn't scope loops and ifs the same way most other languages do, a common issue is the reuse of a variable
declared in such a scope. Usually it doesn't matter, because a reassignment to an already-defined variable will just
reassign it, but if the already-defined variable is a reference it will change the value of the referred to variable.

```php
<?php

$arr = [1, 2, 3];
foreach ($arr as &$i) {
    ++$i;
}

// ...more code, after which the usage of $i as a reference has been forgotten by the programmer

for ($i = 0; $i < 10; ++$i) {
    echo $i;
}
// $arr is now [2, 3, 10] instead of the expected [2, 3, 4]
```

To fix the issue, unset the reference after using it in such a scope:

```php
<?php

$arr = [1, 2, 3];
foreach ($arr as &$i) {
    ++$i;
}
unset($i);

for ($i = 0; $i < 10; ++$i) {
    echo $i;
}
// $arr is correctly [2, 3, 4]
```

---

### Running Psalm Issues ReservedWord (`docs/running_psalm/issues/ReservedWord.md`)

# ReservedWord

Emitted when using a reserved word as a class name

```php
<?php

function foo(resource $res) : void {}
```

---

### Running Psalm Issues RiskyCast (`docs/running_psalm/issues/RiskyCast.md`)

# RiskyCast

Emitted when attempting to cast an array to int or float

```php
<?php

$foo = (int) array( 'hello' );
```

## Why this is bad

The value resulting from the cast depends on if the array is empty or not and can easily lead to off-by-one errors

## How to fix

Don't cast arrays to int or float.

---

### Running Psalm Issues RiskyTruthyFalsyComparison (`docs/running_psalm/issues/RiskyTruthyFalsyComparison.md`)

# RiskyTruthyFalsyComparison

Emitted when comparing a value with multiple types, where at least one type can be only truthy or falsy and other types can contain both truthy and falsy values.

```php
<?php

/**
 * @param array|null $arg
 * @return void
 */
function foo($arg) {
    if ($arg) {
        // this is risky, bc the empty array and null case are handled together
    }
    
    if (!$arg) {
        // this is risky, bc the empty array and null case are handled together  
    }
}
```

## Why this is bad

The truthy/falsy type of a variable is often forgotten and not handled explicitly causing hard to track down errors.

## How to fix

Explicitly validate the variable with strict comparison.

---

### Running Psalm Issues StringIncrement (`docs/running_psalm/issues/StringIncrement.md`)

# StringIncrement

Emitted when incrementing a non-numeric string (`$a = "a"; $a++;` gives `"b"`). This works in PHP,
but is unexpected behaviour for most people, and it is deprecated as of PHP 8.5: use
[`str_increment()`](https://www.php.net/manual/en/function.str-increment.php) (available since
PHP 8.3) instead. The issue is emitted whatever the PHP version the code is analysed for.

```php
<?php

$a = "hello";
$a++;
```

## How to fix

```php
<?php

$a = "hello";
$a = str_increment($a);
```

---

### Running Psalm Issues TaintedCallable (`docs/running_psalm/issues/TaintedCallable.md`)

# TaintedCallable

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when tainted text is used in an arbitrary function call.

This can lead to dangerous situations, like running arbitrary functions.

```php
<?php

$name = $_GET["name"];

evalCode($name);

function evalCode(string $name) {
    if (is_callable($name)) {
        $name();
    }
}
```

---

### Running Psalm Issues TaintedCookie (`docs/running_psalm/issues/TaintedCookie.md`)

# TaintedCookie

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Potential cookie injection. This rule is emitted when user-controlled input can be passed into a cookie.

## Risk

The risk of setting arbitrary cookies depends on further application configuration. 

Examples of potential issues:

- Session Fixation: If the authentication cookie doesn't change after a successful login an attacker could fixate the session cookie. If a victim logs in with a fixated cookie, the attacker can now take over the session of the user.
- Cross-Site-Scripting (XSS): Some application code could read cookies and print it out unsanitized to the user.



## Example

```php
<?php

setcookie('authtoken', $_GET['value'], time() + (86400 * 30), '/');
```

## Mitigations

If this is required functionality, limit the cookie setting to values and not the name. (e.g. `authtoken` in the example)

Make sure to change session tokens after authentication attempts.

## Further resources

- [OWASP Wiki for Session fixation](https://owasp.org/www-community/attacks/Session_fixation)
- [Session Management Cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)
- [CWE-384](https://cwe.mitre.org/data/definitions/384.html)

---

### Running Psalm Issues TaintedCustom (`docs/running_psalm/issues/TaintedCustom.md`)

# TaintedCustom

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when tainted input detection is turned on and custom-tainted data is detected.

---

### Running Psalm Issues TaintedEval (`docs/running_psalm/issues/TaintedEval.md`)

# TaintedEval

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into an `eval` call.

Passing untrusted user input to `eval` calls is dangerous, as it allows arbitrary data to be executed on your server.

```php
<?php

$name = $_GET["name"];

evalCode($name);

function evalCode(string $name) {
    eval($name);
}
```

---

### Running Psalm Issues TaintedExtract (`docs/running_psalm/issues/TaintedExtract.md`)

# TaintedExtract

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled array can be passed into an `extract` call.

```php
<?php

$array = $_GET;
extract($array);
```

---

### Running Psalm Issues TaintedFile (`docs/running_psalm/issues/TaintedFile.md`)

# TaintedFile

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

This rule is emitted when user-controlled input can be passed into a sensitive file operation.

## Risk

The risk here depends on the actual operation that contains user-controlled input, and how it is later on processed.

It could range from:

- Creating files
    - Example: `file_put_contents`
    - Risk: Depending on the server configuration this may result in remote code execution. (e.g. writing a file in the web root)
- Modifying files
    - Example: `file_put_contents`
    - Risk: Depending on the server configuration this may result in remote code execution. (e.g. modifying a PHP file)
- Reading files
    - Example: `file_get_contents`
    - Risk: Sensitive data could be exposed from the filesystem. (e.g. config values, source code, user-submitted files)
- Deleting files
    - Example: `unlink`
    - Risk: Denial of Service or potentially RCE. (e.g. deleting application code, removing a .htaccess file)

curl opens the files some of its options name too. `CURLOPT_COOKIEJAR` writes the cookies the server sends into the file it names, so a server can put PHP code in a file of the attacker's choosing. A `CURLFile` uploads the file it names to the server.

## Example

```php
<?php

unlink($_GET['path']);
```

## Mitigations

Use an allowlist approach where possible to verify names on file operations.

Sanitize user-controlled filenames by stripping `..`, `\` and `/`.

## Further resources

- [File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html)
- [OWASP Wiki for Unrestricted FIle Upload](https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload)
- [CWE-73](https://cwe.mitre.org/data/definitions/73.html)

---

### Running Psalm Issues TaintedHeader (`docs/running_psalm/issues/TaintedHeader.md`)

# TaintedHeader

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Potential header injection. This rule is emitted when user-controlled input can be passed into an HTTP header.

## Risk

The risk of a header injection depends hugely on your environment.

If your webserver supports something like [`XSendFile`](https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/) / [`X-Accel`](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/), an attacker could potentially access arbitrary files on the systems.

If your system does not do that, there may be other concerns, such as:

- Cookie Injection
- Open Redirects
- Proxy Cache Poisoning

The headers of a request the application makes itself are sinks too. Unlike `header()`, curl writes the value of an option such as `CURLOPT_HTTPHEADER`, `CURLOPT_USERAGENT`, `CURLOPT_COOKIE` or `CURLOPT_CUSTOMREQUEST` into the request as is. A line break in it adds headers to the request, for example another `Host` or `Authorization` header. Given to `CURLOPT_CUSTOMREQUEST` or `CURLOPT_REQUEST_TARGET`, it adds a whole other request to the connection. `CURLOPT_QUOTE` sends the FTP or SFTP commands it's given as they are, and `CURLOPT_COOKIELIST` adds cookies to the requests.

## Example

```php
<?php

header($_GET['header']);
```

```php
<?php

$ch = curl_init('https://api.example.com/');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Locale: ' . $_GET['locale']]);
curl_exec($ch);
```

## Mitigations

Make sure only the value and not the key can be set by an attacker. (e.g. `header('Location: ' . $_GET['target']);`)

Verify the set values are sensible. Consider using an allow list. (e.g. for redirections)

For the headers of a request made with curl, reject values containing `\r` or `\n`, and annotate the function doing so with `@psalm-taint-escape header`.

## Further resources

- [Unvalidated Redirects and Forwards Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html)
- [OWASP Wiki for Cache Poisoning](https://owasp.org/www-community/attacks/Cache_Poisoning)
- [CWE-601](https://cwe.mitre.org/data/definitions/601.html)
- [CWE-644](https://cwe.mitre.org/data/definitions/644.html)

---

### Running Psalm Issues TaintedHtml (`docs/running_psalm/issues/TaintedHtml.md`)

# TaintedHtml

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input that can contain HTML can be passed into an `echo` statement.

## Risk

This could lead to a potential Cross Site Scripting (XSS) vulnerability. Using an XSS vulnerability, an attacker could inject malicious JavaScript and execute any action JavaScript could do. Examples include:

- Stealing authentication material (e.g. cookies, JWT tokens)
- Exfiltrate sensitive information by reading the DOM
- Keylog entries on the website (e.g. fake login form)

Whether this is exploitable or not depends on a few conditions:

- Is an executable mimetype set? (e.g. `text/html`)
- Is the content served inline or as attachment? (`Content-Disposition`)
- Is the output properly sanitized? (e.g. stripping all HTML tags or having an allowlist of allowed characters)

## Example

```php
<?php

$name = $_GET["name"];

printName($name);

function printName(string $name) {
    echo $name;
}
```

## Mitigations

- Sanitize user-input by using functions such as `htmlentities` or use an allowlist.
- Set all cookies to `HTTPOnly`.
- Consider using Content Security Policy (CSP), to limit the risk of XSS vulnerabilities.
- If user input itself is HTML, see [Sanitizing HTML User Input](../../security_analysis/avoiding_false_positives.md#sanitizing-html-user-input)

## Further resources

- [OWASP Wiki for Cross Site Scripting (XSS)](https://owasp.org/www-community/attacks/xss/)
- [Content-Security-Policy - Web Fundamentals](https://developers.google.com/web/fundamentals/security/csp)

---

### Running Psalm Issues TaintedInclude (`docs/running_psalm/issues/TaintedInclude.md`)

# TaintedInclude

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into an `include` or `require` expression.

Passing untrusted user input to `include` calls is dangerous, as it can allow an attacker to execute arbitrary scripts on your server.

```php
<?php

$name = $_GET["name"];

includeCode($name);

function includeCode(string $name) : void {
    include($name . '.php');
}
```

---

### Running Psalm Issues TaintedInput (`docs/running_psalm/issues/TaintedInput.md`)

# TaintedInput

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when tainted input detection is turned on

---

### Running Psalm Issues TaintedLdap (`docs/running_psalm/issues/TaintedLdap.md`)

# TaintedLdap

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Potential LDAP injection. This rule is emitted when user-controlled input can be passed into an LDAP request.

## Risk

Passing untrusted user input to LDAP requests could be dangerous. 

If LDAP requests like these are used for login purposes, it could result in an authentication bypass. An attacker could write a filter that would evaluate to `true` for any user, and thus bruteforce credentials easily. 


## Example

```php
<?php

$ds = ldap_connect('example.com');
$dn = 'o=Psalm, c=US';
$filter = $_GET['filter'];
ldap_search($ds, $dn, $filter, []);
```

## Mitigations

Use [`ldap_escape`](https://www.php.net/manual/en/function.ldap-escape.php) to escape user input to the LDAP filter and DN.


## Further resources

- [OWASP Wiki for LDAP Injections](https://owasp.org/www-community/attacks/LDAP_Injection)
- [LDAP Injection Prevention Cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html)
- [CWE-90](https://cwe.mitre.org/data/definitions/90.html)

---

### Running Psalm Issues TaintedLlmPrompt (`docs/running_psalm/issues/TaintedLlmPrompt.md`)

# TaintedLlmPrompt

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into an LLM prompt, risking prompt injection.

```php
<?php

class LlmAgent {
    /** @psalm-taint-sink llm_prompt $prompt */
    public function prompt(string $prompt): string {
        return "";
    }
}

$agent = new LlmAgent();
$agent->prompt((string) $_GET["question"]);
```

---

### Running Psalm Issues TaintedNosql (`docs/running_psalm/issues/TaintedNosql.md`)

# TaintedNosql

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into a NoSQL query (e.g. a MongoDB filter or command).

Unlike SQL injection, NoSQL injection does not depend on string concatenation. It happens
when an attacker controls the *structure* of a query document — typically by supplying an
array/object instead of a scalar. For example, a request like `?username[$ne]=` causes
`$_GET['username']` to be the array `['$ne' => '']`, which turns an equality match into a
"not equal" match and can bypass authentication.

Because of this, only values that can hold an array (or object) can carry the `nosql` taint —
a scalar can never be a NoSQL query, so casting user input to `string`, `int`, `float` or
`bool` removes the taint.

A string decoded back into an array or an object can be a query again, though: what
`json_decode()`, `unserialize()`, `parse_str()`, `parse_ini_string()` and the other decoders
build out of user input carries the `nosql` taint, whatever the type of the string was.

```php
<?php

function getUser(MongoDB\Driver\Manager $manager): array {
    // $_GET["username"] may be an array such as ["$ne" => null]
    $filter = ["username" => $_GET["username"]];
    $query = new MongoDB\Driver\Query($filter);

    return $manager->executeQuery("db.users", $query)->toArray();
}
```

```php
<?php

function findUsers(string $json): MongoDB\Driver\Query {
    // {"username": {"$ne": null}} decodes to a query operator
    return new MongoDB\Driver\Query(json_decode($json, true));
}

findUsers((string) $_POST["filter"]);
```

## Safe alternatives

Cast user input to a scalar so it can only ever be a literal value, never a query operator:

```php
<?php

function getUser(): MongoDB\Driver\Query {
    // (string) forces a literal match; the nosql taint is removed.
    // Casting to (int)/(float)/(bool) works the same way for numeric/boolean fields.
    return new MongoDB\Driver\Query(["username" => (string) $_GET["username"]]);
}
```

Or route the filter through a sanitizer annotated with `@psalm-taint-escape nosql`:

```php
<?php

/**
 * Forces every filter value to a scalar so an attacker cannot inject query
 * operators such as ["$ne" => null] through array-valued input.
 *
 * @param array<string, mixed> $filter
 * @return array<string, string>
 * @psalm-taint-escape nosql
 */
function sanitize_mongo_filter(array $filter): array {
    $safe = [];
    foreach ($filter as $field => $value) {
        if (is_array($value)) {
            throw new InvalidArgumentException("Filter values must be scalar");
        }
        $safe[$field] = (string) $value;
    }
    return $safe;
}

function getUser(): MongoDB\Driver\Query {
    $filter = sanitize_mongo_filter(["username" => $_GET["username"]]);
    return new MongoDB\Driver\Query($filter);
}
```

---

### Running Psalm Issues TaintedSSRF (`docs/running_psalm/issues/TaintedSSRF.md`)

# TaintedSSRF

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Potential Server-Side Request Forgery vulnerability. This rule is emitted when user-controlled input can be passed into a network request.

## Risk

Passing untrusted user input to network requests could be dangerous.

If an attacker can fully control an HTTP request they could connect to internal services. Depending on the nature of these, this can pose a security risk. (e.g. backend services, admin interfaces, AWS metadata, ...)

Besides the URL, the curl options choosing where a request goes or the protocol it uses are reported: a proxy (`CURLOPT_PROXY`), or the hosts not to use it for (`CURLOPT_NOPROXY`), the addresses a name resolves to (`CURLOPT_RESOLVE`), the protocol of a URL without a scheme (`CURLOPT_DEFAULT_PROTOCOL`, which can make it read a local file), the protocols a redirect may use (`CURLOPT_REDIR_PROTOCOLS_STR`), ...

## Example

```php
<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $_GET['url']);

curl_exec($ch);
```

## Mitigations

Mitigating SSRF vulnerabilities can be tricky. Disallowing IPs would likely not work as an attacker could create a malicious domain that points to an internal DNS name.

Consider:

1. Having an allow list of domains that can be connected to.
2. Pointing cURL to a proxy that has no access to internal resources.

## Further resources

- [OWASP Wiki for Server Side Request Forgery](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery)
- [CWE-918](https://cwe.mitre.org/data/definitions/918)

---

### Running Psalm Issues TaintedShell (`docs/running_psalm/issues/TaintedShell.md`)

# TaintedShell

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into an `exec` call or similar.

```php
<?php

$command = $_GET["command"];

runCode($command);

function runCode(string $command) {
    exec($command);
}
```

---

### Running Psalm Issues TaintedSleep (`docs/running_psalm/issues/TaintedSleep.md`)

# TaintedSleep

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into a `sleep` call or similar.

```php
<?php

sleep($_GET["seconds"]);
```

The options making curl throttle a transfer (`CURLOPT_MAX_RECV_SPEED_LARGE`, ...) or wait longer for it (`CURLOPT_TIMEOUT`, ...) are reported too: a client choosing them can keep the request busy as long as it wants.

---

### Running Psalm Issues TaintedSql (`docs/running_psalm/issues/TaintedSql.md`)

# TaintedSql

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into a SQL command.

```php
<?php

class A {
    public function deleteUser(PDO $pdo) : void {
        $userId = self::getUserId();
        $pdo->exec("delete from users where user_id = " . $userId);
    }

    public static function getUserId() : string {
        return (string) $_GET["user_id"];
    }
}
```

---

### Running Psalm Issues TaintedSystemSecret (`docs/running_psalm/issues/TaintedSystemSecret.md`)

# TaintedSystemSecret

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when data marked as a system secret is detected somewhere it shouldn’t be.

```php
<?php

/**
 * @psalm-taint-source system_secret
 */
function getConfigValue(string $data) {
    return "$omePa$$word";
}

echo getConfigValue("secret");
```

---

### Running Psalm Issues TaintedTextWithQuotes (`docs/running_psalm/issues/TaintedTextWithQuotes.md`)

# TaintedTextWithQuotes

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input that can contain quotation marks can be passed into an `echo` statement.

## Risk

This could lead to a potential Cross Site Scripting (XSS) vulnerability. Using an XSS vulnerability, an attacker could inject malicious JavaScript and execute any action JavaScript could do. Examples include:

- Stealing authentication material (e.g. cookies, JWT tokens)
- Exfiltrate sensitive information by reading the DOM
- Keylog entries on the website (e.g. fake login form)

Whether this is exploitable or not depends on a few conditions:

- Is an executable mimetype set? (e.g. `text/html`)
- Is the content served inline or as attachment? (`Content-Disposition`)
- Is the output properly sanitized? (e.g. stripping all HTML tags or having an allowlist of allowed characters)

## Example

```php
<?php
$param = strip_tags($_GET['param']);
?>

<script>
    console.log('<?=$param?>')
</script>
```

Passing `');alert('injection');//` as a `GET` param here would cause the `alert` to trigger.

## Mitigations

- Sanitize user input by using functions such as `htmlentities` with the `ENT_QUOTES` flag or use an allowlist.
- Set all cookies to `HTTPOnly`.
- Consider using Content Security Policy (CSP), to limit the risk of XSS vulnerabilities.
- If user input itself is HTML, see [Sanitizing HTML User Input](../../security_analysis/avoiding_false_positives.md#sanitizing-html-user-input)

## Further resources

- [OWASP Wiki for Cross Site Scripting (XSS)](https://owasp.org/www-community/attacks/xss/)
- [Content-Security-Policy - Web Fundamentals](https://developers.google.com/web/fundamentals/security/csp)

---

### Running Psalm Issues TaintedUnserialize (`docs/running_psalm/issues/TaintedUnserialize.md`)

# TaintedUnserialize

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Tainted input detected to an `unserialize` call.

Passing untrusted user input to `unserialize` calls is dangerous – from the [PHP documentation on unserialize](https://www.php.net/manual/en/function.unserialize.php):

> Do not pass untrusted user input to unserialize() regardless of the options value of allowed_classes. Unserialization can result in code being loaded and executed due to object instantiation and autoloading, and a malicious user may be able to exploit this. Use a safe, standard data interchange format such as JSON (via json_decode() and json_encode()) if you need to pass serialized data to the user.

```php
<?php

$command = $_GET["data"];

getObject($command);

function getObject(string $data) : object {
    return unserialize($data);
}
```

---

### Running Psalm Issues TaintedUrlComponent (`docs/running_psalm/issues/TaintedUrlComponent.md`)

# TaintedUrlComponent

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input is placed, without being URL-encoded, in the path, the query or the fragment of a URL whose server is fixed, and the URL is then requested.

The input can't choose the server the request is sent to (that would be a [TaintedSSRF](TaintedSSRF.md)), but it can still change the request in ways it shouldn't, with URL syntax: `../` to reach another path of the server, `&` to add query parameters or override earlier ones, `#` to cut off the rest of the URL.

## Example

```php
<?php
$query = (string) $_GET['query'];

// with $query = "a&admin=1", this sends ?q=a&admin=1
file_get_contents('https://api.example.com/search?q=' . $query);
```

## Mitigations

Encode the input with `rawurlencode()` or `urlencode()`, or build the query string with `http_build_query()`:

```php
<?php
$query = (string) $_GET['query'];

file_get_contents('https://api.example.com/search?q=' . rawurlencode($query));
file_get_contents('https://api.example.com/search?' . http_build_query(['q' => $query]));
```

In the path of the URL, an encoded value can still be a `..` segment: see [TaintedUrlPath](TaintedUrlPath.md).

## Further resources

- [OWASP Testing Guide: HTTP Parameter Pollution](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/04-Testing_for_HTTP_Parameter_Pollution)
- [CWE-235](https://cwe.mitre.org/data/definitions/235)

---

### Running Psalm Issues TaintedUrlPath (`docs/running_psalm/issues/TaintedUrlPath.md`)

# TaintedUrlPath

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input is placed in the path of a URL whose server is fixed, and the URL is then requested, even once URL-encoded: URL encoding leaves `.` as it is, so the input can still be a `..` segment of the path.

HTTP clients such as cURL resolve these segments before sending the request, so the input can reach another path of the server than the one intended (client-side path traversal).

## Example

```php
<?php
$id = rawurlencode((string) $_GET['id']);

// with $id = "..", this requests https://api.example.com/profile
file_get_contents('https://api.example.com/users/' . $id . '/profile');
```

## Mitigations

Only accept the values the path segment can have, e.g. cast an identifier to `int` or format it with `sprintf('%d')`, or validate it in a function annotated with `@psalm-taint-escape url_path`.

Values placed in the query or the fragment of the URL (after a `?` or a `#`) can't change its path, and aren't reported.

## Further resources

- [OWASP: Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal)
- [CWE-22](https://cwe.mitre.org/data/definitions/22)

---

### Running Psalm Issues TaintedUserSecret (`docs/running_psalm/issues/TaintedUserSecret.md`)

# TaintedUserSecret

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when tainted input detection is turned on and data marked as a user secret is detected somewhere it shouldn’t be.

```php
<?php

class User {
    /**
     * @psalm-taint-source user_secret
     */
    public function getPassword() : string {
        return "$omePa$$word";
    }
}

function showUserPassword(User $user) {
    echo $user->getPassword();
}
```

---

### Running Psalm Issues TaintedXpath (`docs/running_psalm/issues/TaintedXpath.md`)

# TaintedXpath

This is a **security issue**, reported by [security analysis](https://psalm.dev/docs/security_analysis/): it flags a potential vulnerability.

Emitted when user-controlled input can be passed into a xpath query.

```php
<?php

function queryExpression(SimpleXMLElement $xml) : array|false|null {
    $expression = $_GET["expression"];
    return $xml->xpath($expression);
}
```

---

### Running Psalm Issues TooFewArguments (`docs/running_psalm/issues/TooFewArguments.md`)

# TooFewArguments

Emitted when calling a function with fewer arguments than the function has parameters

```php
<?php

function foo(string $a) : void {}
foo();
```

---

### Running Psalm Issues TooManyArguments (`docs/running_psalm/issues/TooManyArguments.md`)

# TooManyArguments

Emitted when calling a function with more arguments than the function has parameters

```php
<?php

function foo(string $a) : void {}
foo("hello", 4);
```

---

### Running Psalm Issues TooManyTemplateParams (`docs/running_psalm/issues/TooManyTemplateParams.md`)

# TooManyTemplateParams

Emitted when using the `@extends`/`@implements` annotation to extend a class and adds too
many types.

```php
<?php

/**
 * @template-implements IteratorAggregate<int, string, int>
 */
class SomeIterator implements IteratorAggregate
{
    public function getIterator() {
        yield 5;
    }
}
```

---

### Running Psalm Issues Trace (`docs/running_psalm/issues/Trace.md`)

# Trace

Not really an issue. Just reports the type of a variable when using
[`@psalm-trace`](../annotating_code/supported_annotations.md#psalm-trace).

```php
<?php

/** @psalm-trace $x */
$x = getmypid();
```

## How to fix

Use it for debugging purposes, not for production

---

### Running Psalm Issues TraitMethodSignatureMismatch (`docs/running_psalm/issues/TraitMethodSignatureMismatch.md`)

# TraitMethodSignatureMismatch

Emitted when a method's signature or return type differs from corresponding trait-defined method

```php
<?php

trait T {
    abstract public function foo(int $i);
}

class A {
    use T;

    public function foo(string $s) : void {}
}
```

---

### Running Psalm Issues TypeDoesNotContainNull (`docs/running_psalm/issues/TypeDoesNotContainNull.md`)

# TypeDoesNotContainNull

Emitted when checking a non-nullable type for `null`

```php
<?php

$a = "hello";
if ($a === null) {}
```

---

### Running Psalm Issues TypeDoesNotContainType (`docs/running_psalm/issues/TypeDoesNotContainType.md`)

# TypeDoesNotContainType

Emitted checking whether one value has a type or value that is impossible given its currently-known type

```php
<?php

$a = "hello";
if ($a === 5) {}
```

---

### Running Psalm Issues UncaughtThrowInGlobalScope (`docs/running_psalm/issues/UncaughtThrowInGlobalScope.md`)

# UncaughtThrowInGlobalScope

Emitted when a possible exception isn't caught in global scope

```php
<?php

/**
 * @throws \Exception
 */
function foo() : int {
    return random_int(0, 1);
}
foo();
```

---

### Running Psalm Issues UndefinedAttributeClass (`docs/running_psalm/issues/UndefinedAttributeClass.md`)

# UndefinedAttributeClass

Emitted when referencing an attribute class that does not exist

```php
<?php
use Foo\Bar\Pure;

#[Pure]
class Video {}
```

---

### Running Psalm Issues UndefinedClass (`docs/running_psalm/issues/UndefinedClass.md`)

# UndefinedClass

Emitted when referencing a class that does not exist

```php
<?php

$a = new A();
```

Is also emitted when using extension classes not added to the `composer.json` requirements or to the [enableExtensions](https://psalm.dev/docs/running_psalm/configuration/#enableextensions) config key.

---

### Running Psalm Issues UndefinedConstant (`docs/running_psalm/issues/UndefinedConstant.md`)

# UndefinedConstant

Emitted when referencing a constant that does not exist

```php
<?php

echo FOO_BAR;
```

Is also emitted when using extension constants not added to the `composer.json` requirements or to the [enableExtensions](https://psalm.dev/docs/running_psalm/configuration/#enableextensions) config key.

---

### Running Psalm Issues UndefinedDocblockClass (`docs/running_psalm/issues/UndefinedDocblockClass.md`)

# UndefinedDocblockClass

Emitted when referencing a class that does not exist from a docblock

```php
<?php

/**
 * @param DoesNotExist $a
 */
function foo($a) : void {}
```

---

### Running Psalm Issues UndefinedFunction (`docs/running_psalm/issues/UndefinedFunction.md`)

# UndefinedFunction

Emitted when referencing a function that doesn't exist

```php
<?php

foo();
```

Is also emitted when using extension functions not added to the `composer.json` requirements or to the [enableExtensions](https://psalm.dev/docs/running_psalm/configuration/#enableextensions) config key.

---

### Running Psalm Issues UndefinedGlobalVariable (`docs/running_psalm/issues/UndefinedGlobalVariable.md`)

# UndefinedGlobalVariable

Emitted when referencing a variable that doesn't exist

```php
<?php

echo $a;
```

---

### Running Psalm Issues UndefinedInterface (`docs/running_psalm/issues/UndefinedInterface.md`)

# UndefinedInterface

Emitted when referencing an interface that does not exist but does have an identically-named class.

```php
<?php

class C {}

interface I extends C {}
```

---

### Running Psalm Issues UndefinedInterfaceMethod (`docs/running_psalm/issues/UndefinedInterfaceMethod.md`)

# UndefinedInterfaceMethod

Emitted when calling a method that does not exist on an interface

```php
<?php

interface I {}

function foo(I $i) {
    $i->bar();
}
```

---

### Running Psalm Issues UndefinedMagicMethod (`docs/running_psalm/issues/UndefinedMagicMethod.md`)

# UndefinedMagicMethod

Emitted when calling a magic method that does not exist

```php
<?php

/**
 * @method bar():string
 */
class A {
    public function __call(string $name, array $args) {
        return "cool";
    }
}
(new A)->foo();
```

To fix, add all used magic methods as `@method` annotations: 

```php
<?php

/**
 * @method bar():string
 * @method foo():string
 */
class A {
    public function __call(string $name, array $args) {
        return "cool";
    }
}
(new A)->foo();
```


Or, **only if** dealing with generic wrapper objects (like `FFI` classes), use `@psalm-no-seal-methods`.  
Try to avoid using `@psalm-no-seal-methods`, as it worsens type coverage, and is not needed in the vast majority of cases.

---

### Running Psalm Issues UndefinedMagicPropertyAssignment (`docs/running_psalm/issues/UndefinedMagicPropertyAssignment.md`)

# UndefinedMagicPropertyAssignment

Emitted when assigning a property on an object that does not have that magic property defined

```php
<?php

/**
 * @property string $bar
 */
class A {
    /** @param mixed $value */
    public function __set(string $name, $value) {}
}
$a = new A();
$a->foo = "bar";
```

To fix, add all used magic properties as `@property` annotations: 

```php
<?php

/**
 * @property string $bar
 * @property string $foo
 */
class A {
    /** @param mixed $value */
    public function __set(string $name, $value) {}
}
$a = new A();
$a->foo = "bar";
```

Or, **only if** dealing with generic container objects (like `ArrayObject`), use `@psalm-no-seal-properties`.

```php
<?php

/** @psalm-no-seal-properties */
class ArrayBag {
    public function __construct(private array $arr = []) {}
    public function __set(string $k, mixed $v) {
        $this->arr[$k] = $v;
    }
    public function __get(string $k): mixed {
        return $this->arr[$k];
    }
}
$a = new ArrayBag(['bar' => 'foo']);
$a->foo = "bar";
```

---

### Running Psalm Issues UndefinedMagicPropertyFetch (`docs/running_psalm/issues/UndefinedMagicPropertyFetch.md`)

# UndefinedMagicPropertyFetch

Emitted when getting a property on an object that does not have that magic property defined

```php
<?php

/**
 * @property string $bar
 */
class A {
    public function __get(string $name) {
        return "cool";
    }
}
$a = new A();
echo $a->foo;
```

To fix, add all used magic properties as `@property` annotations: 

```php
<?php

/**
 * @property string $bar
 * @property string $foo
 */
class A {
    /** @param mixed $value */
    public function __set(string $name, $value) {}
}
$a = new A();
echo $a->foo;
```

Or, **only if** dealing with generic container objects (like `ArrayObject`), use `@psalm-no-seal-properties`.

```php
<?php

/** @psalm-no-seal-properties */
class ArrayBag {
    public function __construct(private array $arr = []) {}
    public function __set(string $k, mixed $v) {
        $this->arr[$k] = $v;
    }
    public function __get(string $k): mixed {
        return $this->arr[$k];
    }
}
$a = new ArrayBag(['bar' => 'foo']);
echo $a->bar;
```

---

### Running Psalm Issues UndefinedMethod (`docs/running_psalm/issues/UndefinedMethod.md`)

# UndefinedMethod

Emitted when calling a method that does not exist

```php
<?php

class A {}
A::foo();
```

---

### Running Psalm Issues UndefinedPropertyAssignment (`docs/running_psalm/issues/UndefinedPropertyAssignment.md`)

# UndefinedPropertyAssignment

Emitted when assigning a property on an object that does not have that property defined

```php
<?php

class A {}
$a = new A();
$a->foo = "bar";
```

---

### Running Psalm Issues UndefinedPropertyFetch (`docs/running_psalm/issues/UndefinedPropertyFetch.md`)

# UndefinedPropertyFetch

Emitted when getting a property on an object that does not have that property defined

```php
<?php

class A {}
$a = new A();
echo $a->foo;
```

---

### Running Psalm Issues UndefinedThisPropertyAssignment (`docs/running_psalm/issues/UndefinedThisPropertyAssignment.md`)

# UndefinedThisPropertyAssignment

Emitted when assigning a property on an object in one of that object’s methods when no such property exists

```php
<?php

class A {
    function foo() {
        $this->foo = "bar";
    }
}
```

---

### Running Psalm Issues UndefinedThisPropertyFetch (`docs/running_psalm/issues/UndefinedThisPropertyFetch.md`)

# UndefinedThisPropertyFetch

Emitted when getting a property for an object in one of that object’s methods when no such property exists

```php
<?php

class A {
    function foo() {
        echo $this->foo;
    }
}
```

---

### Running Psalm Issues UndefinedTrace (`docs/running_psalm/issues/UndefinedTrace.md`)

# UndefinedTrace

Attempt to trace an undefined variable

```php
<?php

/** @psalm-trace $x */
echo 'Hello World!';
```

## How to fix

Provide existing variable or remove it

---

### Running Psalm Issues UndefinedTrait (`docs/running_psalm/issues/UndefinedTrait.md`)

# UndefinedTrait

Emitted when referencing a trait that does not exist

```php
<?php

class A {
    use T;
}
```

---

### Running Psalm Issues UndefinedVariable (`docs/running_psalm/issues/UndefinedVariable.md`)

# UndefinedVariable

Emitted when referencing a variable that doesn't exist in a given function’s scope

```php
<?php

function foo() {
    echo $a;
}
```

---

### Running Psalm Issues UnevaluatedCode (`docs/running_psalm/issues/UnevaluatedCode.md`)

# UnevaluatedCode

Emitted when `--find-dead-code` is turned on and Psalm encounters code that will not be evaluated

```php
<?php

function foo() : void {
    return;
    $a = "foo";
}
```

---

### Running Psalm Issues UnhandledMatchCondition (`docs/running_psalm/issues/UnhandledMatchCondition.md`)

# UnhandledMatchCondition

Emitted when a match expression does not handle one or more options.

```php
<?php

function matchOne(): string {
    $foo = rand(0, 1) ? "foo" : "bar";

    return match ($foo) {
        'foo' => 'foo',
    };
}
```

## Why this is bad

The above code will fail 50% of the time with an `UnhandledMatchError` error.

---

### Running Psalm Issues UnimplementedAbstractMethod (`docs/running_psalm/issues/UnimplementedAbstractMethod.md`)

# UnimplementedAbstractMethod

Emitted when a class extends another, but does not implement all of its abstract methods

```php
<?php

abstract class A {
    abstract public function foo() : void;
}
class B extends A {}
```

---

### Running Psalm Issues UnimplementedInterfaceMethod (`docs/running_psalm/issues/UnimplementedInterfaceMethod.md`)

# UnimplementedInterfaceMethod

Emitted when a class `implements` an interface but does not implement all of its methods

```php
<?php

interface I {
    public function foo() : void;
}
class A implements I {}
```

---

### Running Psalm Issues UninitializedProperty (`docs/running_psalm/issues/UninitializedProperty.md`)

# UninitializedProperty

Emitted when a property is used in a constructor before it is initialized

```php
<?php

class A {
    /** @var string */
    public $foo;

    public function __construct() {
        echo strlen($this->foo);
        $this->foo = "foo";
    }
}
```

---

### Running Psalm Issues UnnecessaryVarAnnotation (`docs/running_psalm/issues/UnnecessaryVarAnnotation.md`)

# UnnecessaryVarAnnotation

Emitted when `--find-dead-code` is turned on and you're using a `@var` annotation on an assignment that Psalm has already identified a type for.

```php
<?php

function foo() : string {
    return "hello";
}

/** @var string */
$a = foo();
```

---

### Running Psalm Issues UnrecognizedExpression (`docs/running_psalm/issues/UnrecognizedExpression.md`)

# UnrecognizedExpression

Emitted when Psalm encounters an expression that it doesn't know how to handle. This should never happen.

---

### Running Psalm Issues UnrecognizedStatement (`docs/running_psalm/issues/UnrecognizedStatement.md`)

# UnrecognizedStatement

Emitted when Psalm encounters a code construct that it doesn't know how to handle. This should never happen.

---

### Running Psalm Issues UnresolvableConstant (`docs/running_psalm/issues/UnresolvableConstant.md`)

# UnresolvableConstant

Emitted when Psalm cannot resolve a constant used in `key-of` or `value-of`. Note that `static::CONST` is considered
unresolvable for `key-of` and `value-of`, since the literal keys and values can't be resolved due to the possibility
of being overridden by child classes.

```php
<?php

class Foo
{
    public const BAR = ['bar'];

    /**
     * @return value-of<self::BAT>
     */
    public function bar(): string
    {
        return self::BAR[0];
    }
}
```

---

### Running Psalm Issues UnresolvableInclude (`docs/running_psalm/issues/UnresolvableInclude.md`)

# UnresolvableInclude

Emitted when Psalm cannot figure out what specific file is being included/required by PHP.

```php
<?php

function requireFile(string $s) : void {
    require_once $s;
}
```

---

### Running Psalm Issues UnsafeGenericInstantiation (`docs/running_psalm/issues/UnsafeGenericInstantiation.md`)

# UnsafeGenericInstantiation

Emitted when an attempt is made to instantiate a class using `new static` without a constructor that's final:

```php
<?php

/**
 * @template T
 * @psalm-consistent-constructor
 */
class Container {
    /**
     * @var T
     */
    public $t;

    /**
     * @param T $t
     */
    public function __construct($t) {
        $this->t = $t;
    }

    /**
     * @template U
     * @param U $u
     * @return static<U>
     */
    public function getInstance($u) : static
    {
        return new static($u);
    }
}
```


## What’s wrong here?

The problem comes when extending the class:

```php
<?php

/**
 * @template T
 * @psalm-consistent-constructor
 */
class Container {
    /**
     * @var T
     */
    public $t;

    /**
     * @param T $t
     */
    public function __construct($t) {
        $this->t = $t;
    }

    /**
     * @template U
     * @param U $u
     * @return static<U>
     */
    public function getInstance($u) : static
    {
        return new static($u);
    }
}

/**
 * @extends Container<string>
 */
class StringContainer extends Container {}

$c = StringContainer::getInstance(new stdClass());
// creates StringContainer<stdClass>, clearly invalid
```

## How to fix

Either use `new self` instead of `new static`:

```php
<?php

/**
 * @template T
 * @psalm-consistent-constructor
 */
class Container {
    /**
     * @var T
     */
    public $t;

    /**
     * @param T $t
     */
    public function __construct($t) {
        $this->t = $t;
    }

    /**
     * @template U
     * @param U $u
     * @return self<U>
     */
    public function getInstance($u) : self
    {
        return new self($u);
    }
}
```

Or you can add a `@psalm-consistent-templates` annotation which ensures that any child class has the same generic params:

```php
<?php

/**
 * @template T
 * @psalm-consistent-constructor
 * @psalm-consistent-templates
 */
class Container {
    /**
     * @var T
     */
    public $t;

    /**
     * @param T $t
     */
    public function __construct($t) {
        $this->t = $t;
    }

    /**
     * @template U
     * @param U $u
     * @return static<U>
     */
    public function getInstance($u) : static
    {
        return new static($u);
    }
}

/**
 * @template T
 * @psalm-extends Container<T>
 */
class LazyLoadingContainer extends Container {}
```

A purity template (`@psalm-purity-template`) only makes `new static()` unsafe when the constructor's
parameters take it (`Closure[C]`): the arguments cannot infer the others, only the child classes bind them.

---

### Running Psalm Issues UnsafeInstantiation (`docs/running_psalm/issues/UnsafeInstantiation.md`)

# UnsafeInstantiation

Emitted when an attempt is made to instantiate a class using `new static` or similar without a constructor that's final:

```php
<?php

class A {
    public function getInstance() : self
    {
        return new static();
    }
}
```

## What’s wrong here?

The problem comes when extending the class:

```php
<?php

class A {
    public function getInstance() : self
    {
        return new static();
    }
}

class AChild extends A {
    public function __construct(string $some_required_param) {}
}

AChild::getInstance(); // fatal error
```

## How to fix

You have two options – you can make the constructor final:

```php
<?php

class A {
    final public function __construct() {}

    public function getInstance() : self
    {
        return new static();
    }
}
```

Or you can add a `@psalm-consistent-constructor` annotation which ensures that any constructor in a child class has the same signature as the parent constructor:

```php
<?php

/**
 * @psalm-consistent-constructor
 */
class A {
    public function getInstance() : self
    {
        return new static();
    }
}

class AChild extends A {
    public function __construct() {
        // this is fine
    }
}

class BadAChild extends A {
    public function __construct(string $s) {
        // this is reported as a violation
    }
}
```

---

### Running Psalm Issues UnsupportedPropertyReferenceUsage (`docs/running_psalm/issues/UnsupportedPropertyReferenceUsage.md`)

# UnsupportedPropertyReferenceUsage

Psalm cannot guarantee the soundness of code that uses references to properties.

### Examples of Uncaught Errors

* Instance property assigned wrong type:
```php
<?php
class A {
    public int $b = 0;
}
$a = new A();
$b = &$a->b;
$b = ''; // Fatal error
```

* Static property assigned wrong type:
```php
<?php
class A {
    public static int $b = 0;
}
$b = &A::$b;
$b = ''; // Fatal error
```

* Readonly property reassigned:
```php
<?php
class A {
    public function __construct(
        public readonly int $b,
    ) {
    }
}
$a = new A(0);
$b = &$a->b;
$b = 1; // Fatal error
```

---

### Running Psalm Issues UnsupportedReferenceUsage (`docs/running_psalm/issues/UnsupportedReferenceUsage.md`)

# UnsupportedReferenceUsage

Emitted when Psalm encounters a reference that it is not currently able to track (for instance a reference to an array
offset of an array offset: `$foo = &$bar[$baz[0]]`). When an unsupported reference is encountered, Psalm will issue this
warning and treat the variable as though it wasn't actually a reference.

## How to fix

This can sometimes be fixed by using a temporary variable:

```php
<?php

/** @var non-empty-list<int> */
$bar = [1, 2, 3];
/** @var non-empty-list<int> */
$baz = [1, 2, 3];

$foo = &$bar[$baz[0]];
```

can be turned into

```php
<?php

/** @var non-empty-list<int> */
$bar = [1, 2, 3];
/** @var non-empty-list<int> */
$baz = [1, 2, 3];

$offset = $baz[0];
$foo = &$bar[$offset];
```

---

### Running Psalm Issues UnusedBaselineEntry (`docs/running_psalm/issues/UnusedBaselineEntry.md`)

# UnusedBaselineEntry

Emitted when a baseline entry is not being used to suppress an issue.

Enabled by [findUnusedBaselineEntry](../configuration.md#findunusedbaselineentry) 

```php
<?php
$a = 'Hello, World!';
echo $a;
```
```xml
<?xml version="1.0" encoding="UTF-8"?>
<files>
    <file src="example.php">
        <UnusedVariable>
            
            <code>$a</code>
        </UnusedVariable>
    </file>
</files>
```

---

### Running Psalm Issues UnusedClass (`docs/running_psalm/issues/UnusedClass.md`)

# UnusedClass

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a
given class.

If this class is genuinely part of your public API — used from outside the analysed codebase (for example a library entry point, or a class instantiated only by a framework or plugin loader) — annotate it with `@api` (or `@psalm-api`); use this only for real public surface. Otherwise the class is dead code and should be removed.

See [`@api`](../../annotating_code/supported_annotations.md#api-psalm-api) for the full guidance; note that `@psalm-suppress` is not a substitute for `@api`, as it silences the report without marking the class as used.

```php
<?php

final class A {}
final class B {}
$a = new A();
```

---

### Running Psalm Issues UnusedClosureParam (`docs/running_psalm/issues/UnusedClosureParam.md`)

# UnusedClosureParam

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a particular parameter in a closure.

```php
<?php

$a = function (int $a, int $b) : int {
    return $a + 4;
};

/**
 * @param callable(int,int):int $c
 */
function foo(callable $c) : int {
    return $c(2, 4);
}
```

Can be suppressed by prefixing the parameter name with an underscore:

```php
$f = function (int $_a, int $b) : int {
    return $b + 4;
};
```

---

### Running Psalm Issues UnusedConstructor (`docs/running_psalm/issues/UnusedConstructor.md`)

# UnusedConstructor

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a given private constructor or function

```php
<?php

class A {
    private function __construct() {}

    public static function createInstance() : void {}
}
A::createInstance();
```

---

### Running Psalm Issues UnusedDocblockParam (`docs/running_psalm/issues/UnusedDocblockParam.md`)

# UnusedDocblockParam

Emitted when `--find-dead-code` is turned on and a parameter specified in docblock does not have a corresponding parameter in function / method signature.

```php
<?php

/**
 * @param string $legacy_param was renamed to $newParam
 */
function f(string $newParam): string {
    return strtolower($newParam);
}
```

---

### Running Psalm Issues UnusedForeachValue (`docs/running_psalm/issues/UnusedForeachValue.md`)

# UnusedForeachValue

Emitted when `--find-dead-code` is turned on and Psalm cannot find any
references to the foreach value

```php
<?php

/** @param array<string, int> $a */
function foo(array $a) : void {
    foreach ($a as $key => $value) { // $value is unused
        echo $key;
    }
}
```

Can be suppressed by prefixing the variable name with an underscore or naming
it `$_`:

```php
<?php

foreach ([1, 2, 3] as $key => $_val) {}

foreach ([1, 2, 3] as $key => $_) {}
```

---

### Running Psalm Issues UnusedFunctionCall (`docs/running_psalm/issues/UnusedFunctionCall.md`)

# UnusedFunctionCall

Emitted when `--find-dead-code` is turned on and Psalm finds a function call whose return value is not used anywhere

```php
<?php

$a = strlen("hello");
strlen("goodbye"); // unused
echo $a;
```

It is also emitted, regardless of `--find-dead-code`, when the return value of a function annotated with PHP 8.5's `#[\NoDiscard]` attribute is discarded. Casting the call to `(void)` intentionally discards the value without triggering the issue.

---

### Running Psalm Issues UnusedIssueHandlerSuppression (`docs/running_psalm/issues/UnusedIssueHandlerSuppression.md`)

# UnusedIssueHandlerSuppression

Emitted when an issue type suppression in the configuration file is not being used to suppress an issue.

Enabled by [findUnusedIssueHandlerSuppression](../configuration.md#findunusedissuehandlersuppression) 

```php
<?php
$a = 'Hello, World!';
echo $a;
```
```xml
<?xml version="1.0" encoding="UTF-8"?>
<issueHandlers>
    <PossiblyNullOperand errorLevel="suppress"/>
</issueHandlers>
```

---

### Running Psalm Issues UnusedMethod (`docs/running_psalm/issues/UnusedMethod.md`)

# UnusedMethod

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a
given private method or function.

If this method is genuinely part of your public API — used from outside the analysed codebase (for example a library entry point, or a method invoked only by a framework) — annotate the containing class with `@api` (or `@psalm-api`) — mark the whole class rather than the individual method, since a public-API method almost always belongs to a public-API class. Otherwise the method is dead code and should be removed: a method reported as unused in a class that is **not** already marked `@api` is almost always genuinely unused, so annotating the individual method with `@api` to silence the report is very rarely the right fix.

See [`@api`](../../annotating_code/supported_annotations.md#api-psalm-api) for the full guidance; note that `@psalm-suppress` is not a substitute for `@api`, as it silences the report without marking the method as used.

```php
<?php

class A {
    public function __construct() {
        $this->foo();
    }
    private function foo() : void {}
    private function bar() : void {}
}
$a = new A();
```

---

### Running Psalm Issues UnusedMethodCall (`docs/running_psalm/issues/UnusedMethodCall.md`)

# UnusedMethodCall

Emitted when `--find-dead-code` is turned on and Psalm finds a method call whose return value is not used anywhere

```php
<?php

final class A {
    private string $foo;

    public function __construct(string $foo) {
        $this->foo = $foo;
    }

    public function getFoo() : string {
        return $this->foo;
    }
}

$a = new A("hello");
$a->getFoo();
```

It is also emitted, regardless of `--find-dead-code`, when the return value of a method annotated with PHP 8.5's `#[\NoDiscard]` attribute is discarded. Casting the call to `(void)` intentionally discards the value without triggering the issue.

---

### Running Psalm Issues UnusedParam (`docs/running_psalm/issues/UnusedParam.md`)

# UnusedParam

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a particular parameter in a private method or function:

```php
<?php

function foo(int $a, int $b) : int {
    return $a + 4;
}
```

Can be suppressed by prefixing the unused parameter's name with an underscore:

```php
function foo(int $a, int $_b) : int {
    return $a + 4;
}
```

---

### Running Psalm Issues UnusedProperty (`docs/running_psalm/issues/UnusedProperty.md`)

# UnusedProperty

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a
private property.

Properties used in constructor only are considered unused. Use normal variables instead.

If this property is genuinely part of your public API — used from outside the analysed codebase (for example a library entry point, or a property read only by a framework) — annotate the containing class with `@api` (or `@psalm-api`) — mark the whole class rather than the individual property, since a public-API property almost always belongs to a public-API class. Otherwise the property is dead code and should be removed: a property reported as unused in a class that is **not** already marked `@api` is almost always genuinely unused, so annotating the individual property with `@api` to silence the report is very rarely the right fix.

See [`@api`](../../annotating_code/supported_annotations.md#api-psalm-api) for the full guidance; note that `@psalm-suppress` is not a substitute for `@api`, as it silences the report without marking the property as used.

```php
<?php

class A {
    /** @var string|null */
    private $foo;

    /** @var int|null */
    private $bar;

    public function getFoo(): ?string {
        return $this->foo;
    }
}

$a = new A();
echo $a->getFoo();
```

---

### Running Psalm Issues UnusedPsalmSuppress (`docs/running_psalm/issues/UnusedPsalmSuppress.md`)

# UnusedPsalmSuppress

Emitted when `--find-unused-psalm-suppress` is turned on and Psalm cannot find any uses of a given `@psalm-suppress` annotation

```php
<?php

/** @psalm-suppress InvalidArgument */
echo strlen("hello");
```

This is checked for `@psalm-suppress` annotations in any docblock, including those on classes, interfaces, traits and enums. `@psalm-suppress` of `Tainted*` issues is only checked when running with `--taint-analysis`, since those issues are not computed otherwise.

---

### Running Psalm Issues UnusedReturnValue (`docs/running_psalm/issues/UnusedReturnValue.md`)

# UnusedReturnValue

Emitted when `--find-dead-code` is turned on and Psalm cannot find any uses of a private method’s return value.

```php
<?php

class A {
    public function __construct() {
        $this->foo();
    }
    private function foo() : string {
        return "hello";
    }
}

new A();
```

---

### Running Psalm Issues UnusedVariable (`docs/running_psalm/issues/UnusedVariable.md`)

# UnusedVariable

Emitted when `--find-dead-code` is turned on and Psalm cannot find any references to a variable, once instantiated

```php
<?php

function foo() : void {
    $a = 5;
    $b = 4;
    echo $b;
}
```

Can be suppressed by prefixing the variable name with an underscore:

```php
<?php

$_a = 22;
```


If the variable contains an object with an impure destructor, the issue is not emitted, to allow for patterns used for example in timers or mutexes:

```php
<?php

class Timer {
    private readonly float $start;
    public function __construct(private readonly string $op) {
        $this->start = microtime(true);
    }
    /**
     * Must be explicitly marked as @psalm-impure.
     * 
     * @psalm-impure
     */
    public function __destruct() {
        $took = microtime(true) - $this->start;
        // Send to influx, or similar
        echo "{$this->op} took $took seconds!\n";
    }
}

function foo() : void {
    // OK!
    $timer = new Timer('file_get_contents');

    echo file_get_contents('https://httpbin.io/delay/3');
}

foo();

$var = [new Timer('bad')];

// UnusedVariable: The issue will still be emitted even if the destructor is impure for variables used as foreach variables.
foreach ($var as $timer) {

}
```

---

### Running Psalm Plugins Authoring Plugins (`docs/running_psalm/plugins/authoring_plugins.md`)

# Authoring Plugins

## Quick start

### Using a template repository

Head over to [plugin template repository](https://github.com/psalm/psalm-plugin-skeleton) on GitHub, login and click `Use this template` button.

### Using skeleton project

Run `composer create-project psalm/psalm-plugin-skeleton:dev-master your-plugin-name` to quickly bootstrap a new plugin project in `your-plugin-name` folder. Make sure you adjust namespaces in `composer.json`, `Plugin.php` and `tests` folder.

## Psalm plugin API

Backwards compatibility for the plugin API is now covered by a separate metapackage, [psalm/psalm-plugin-api](https://packagist.org/packages/psalm/psalm-plugin-api).  

This is a separate, empty metapackage: its major version will be bumped every time a breaking change occurs within Psalm's plugin API; minors will also be bumped when adding new features to Psalm's plugin API.  

Plugins, starting from the first stable release of v7, need to explicitly require a caret range (i.e. ^1, NOT 1.0.0) that package in order to avoid breaking changes during Psalm upgrades.  

Plugins that support v7 betas can already require `0.x` versions of the package.  

All plugin API versions with a list of contained breaking changes will be listed in the readme of [psalm/psalm-plugin-api](https://packagist.org/packages/psalm/psalm-plugin-api).  

## Stub files

Stub files provide a way to override third-party type information when you cannot add Psalm's extended docblocks to the upstream source files directly.
By convention, stub files have `.phpstub` extension to avoid IDEs treating them as actual php code.

## Generating stubs

Dev-require the library you want to tweak types for, e.g.
```
composer require --dev cakephp/chronos
```
Then generate the stubs
```
vendor/bin/psalm --generate-stubs=stubs/chronos.phpstub
```
Open the generated file and remove everything not related to the library you're stubbing. Tweak the docblocks to provide more accurate types.

## Registering stub files

Skeleton/template project includes the code to register all `.phpstub` files from the `stubs` directory.

To register a stub file manually use `Psalm\Plugin\RegistrationInterface::addStubFile()`.

## Registering custom scanners and analyzers

In addition to XML configuration node `<fileExtensions>` plugins can register their own custom scanner
and analyzer implementations for particular file extensions, e.g.

* `Psalm\Plugin\FileExtensionsInterface::addFileTypeScanner('html', CustomFileScanner::class)`
* `Psalm\Plugin\FileExtensionsInterface::addFileTypeAnalyzer('html', CustomFileAnalyzer::class)`

## Publishing your plugin on Packagist

Follow instructions on packagist.org under 'Publishing Packages' section.

## Advanced topics

### Starting from scratch

Composer-based plugin is a composer package which conforms to these requirements:

1. Its `type` field is set to `psalm-plugin`
2. It has `extra.psalm.pluginClass` subkey in its `composer.json` that reference an entry-point class that will be invoked to register the plugin into Psalm runtime.
3. Entry-point class implements `Psalm\Plugin\PluginEntryPointInterface`

### Psalm API

Plugins may implement one of (or more than one of) `Psalm\Plugin\EventHandler\*` interface(s).

```php
<?php
class SomePlugin implements \Psalm\Plugin\EventHandler\AfterStatementAnalysisInterface
{
}
```

`Psalm\Plugin\EventHandler\*` offers the following interfaces that you can implement:

- `AfterAnalysisInterface` - called after Psalm has completed its analysis. Use this hook if you want to do something with the analysis results.
- `AfterClassLikeAnalysisInterface` - called after Psalm has completed its analysis of a given class.
- `AfterClassLikeExistenceCheckInterface` - called after Psalm analyzes a reference to a class, interface or trait.
- `AfterClassLikeVisitInterface` - called after Psalm crawls the parsed Abstract Syntax Tree for a class-like (class, interface, trait). Due to caching the AST is crawled the first time Psalm sees the file, and is only re-crawled if the file changes, the cache is cleared, or you're disabling cache with `--no-cache`/`--no-reflection-cache`. Use this if you want to collect or modify information about a class before Psalm begins its analysis.
- `AfterCodebasePopulatedInterface` - called after Psalm has scanned necessary files and populated codebase data.
- `AfterEveryFunctionCallAnalysisInterface` - called after Psalm evaluates any function call. Cannot influence the call further.
- `AfterExpressionAnalysisInterface` - called after Psalm evaluates an expression.
- `AfterFileAnalysisInterface` - called after Psalm analyzes a file.
- `AfterFunctionCallAnalysisInterface` - called after Psalm evaluates a function call to any function defined within the project itself. Can alter the return type or perform modifications of the call.
- `AfterFunctionLikeAnalysisInterface` - called after Psalm has completed its analysis of a given function-like.
- `AfterMethodCallAnalysisInterface` - called after Psalm analyzes a method call.
- `BeforeStatementAnalysisInterface` - called before Psalm evaluates a statement.
- `AfterStatementAnalysisInterface` - called after Psalm evaluates a statement.
- `BeforeAddIssueInterface` - called before Psalm adds an item to it's internal `IssueBuffer`, allows handling code issues individually
- `BeforeFileAnalysisInterface` - called before Psalm analyzes a file.
- `ClassFilePathProviderInterface.php` - can be used to determine the file path a of a class not autoloadable using composer, but autoloadable through a custom autoloader, to avoid actually invoking the autoloader and executing the class
- `FunctionExistenceProviderInterface` - can be used to override Psalm's builtin function existence checks for one or more functions.
- `FunctionParamsProviderInterface.php` - can be used to override Psalm's builtin function parameter lookup for one or more functions.
- `FunctionReturnTypeProviderInterface` - can be used to override Psalm's builtin function return type lookup for one or more functions.
- `MethodCapabilitiesProviderInterface` - can be used to give the capabilities (purity) a call of a method of one or more classes requires, e.g. from its arguments.
- `MethodExistenceProviderInterface` - can be used to override Psalm's builtin method existence checks for one or more classes.
- `MethodParamsProviderInterface` - can be used to override Psalm's builtin method parameter lookup for one or more classes.
- `MethodReturnTypeProviderInterface` - can be used to override Psalm's builtin method return type lookup for one or more classes.
- `MethodVisibilityProviderInterface` - can be used to override Psalm's builtin method visibility checks for one or more classes.
- `PropertyExistenceProviderInterface` - can be used to override Psalm's builtin property existence checks for one or more classes.
- `PropertyTypeProviderInterface` - can be used to override Psalm's builtin property type lookup for one or more classes.
- `PropertyVisibilityProviderInterface` - can be used to override Psalm's builtin property visibility checks for one or more classes.
- `DynamicFunctionStorageProviderInterface` - can be used to override signature for one or more functions. It means you can define variadic param list. Infer return type by input args. Define function templates. Also check out `Psalm\Plugin\DynamicFunctionStorage` to find out what api it brings for you to change function's definition.

Here are a couple of example plugins:
 - [StringChecker](https://github.com/vimeo/psalm/blob/master/examples/plugins/StringChecker.php) - checks class references in strings
 - [PreventFloatAssignmentChecker](https://github.com/vimeo/psalm/blob/master/examples/plugins/PreventFloatAssignmentChecker.php) - prevents assignment to floats
 - [FunctionCasingChecker](https://github.com/vimeo/psalm/blob/master/examples/plugins/FunctionCasingChecker.php) - checks that your functions and methods are correctly-cased

To ensure your plugin runs when Psalm does, add it to your [config](../configuration.md) (not needed for composer-based plugins):
```xml
    <plugins>
        <plugin filename="src/plugins/SomePlugin.php" />
    </plugins>
```

You can also specify an absolute path to your plugin:
```xml
    <plugins>
        <plugin filename="/path/to/SomePlugin.php" />
    </plugins>
```

### Using Xdebug

As Psalm disables _Xdebug_ at runtime, if you need to debug your code step-by-step when authoring a plugin, you can allow the extension by running Psalm as following:

```console
$ PSALM_ALLOW_XDEBUG=1 path/to/psalm
```

## Type system

Understand how Psalm handles types by [reading this guide](plugins_type_system.md).

## Handling custom plugin issues

Plugins may sometimes need to emit their own issues (i.e. not emit one of the [existing issues](../issues.md)). If this is the case, they can emit an issue that extends `Psalm\Issue\PluginIssue`.

To suppress a custom plugin issue in docblocks you can just use its issue name (e.g. `/** @psalm-suppress NoFloatAssignment */`, but to [suppress it in Psalm’s config](../dealing_with_code_issues.md#config-suppression) you must use the pattern:

```xml
<PluginIssue name="NoFloatAssignment" errorLevel="suppress" />
```

You can also use more complex rules in the `<issueHandler />` element, as you can with any other issue type e.g.

```xml
<PluginIssue name="NoFloatAssignment">
    <errorLevel type="suppress">
        <directory name="tests" />
    </errorLevel>
</PluginIssue>
```

## Upgrading file-based plugin to composer-based version

Create new plugin project using skeleton, then pass the class name of you file-based plugin to `registerHooksFromClass()`
method of the `Psalm\Plugin\RegistrationInterface` instance that was passed into your plugin entry point's `__invoke()`
method. See the [conversion example](https://github.com/vimeo/psalm/tree/master/examples/plugins/composer-based/echo-checker/).

---

### Running Psalm Plugins Plugins Type System (`docs/running_psalm/plugins/plugins_type_system.md`)

# Plugins: type system internals

Psalm's type system represents the types of variables within a program using different classes. Plugins both receive, and can update this type information.

## Union types

All type information you are likely to use will be wrapped in a [Union Type](../../annotating_code/type_syntax/union_types.md).

The `Union` class constructor takes an array of `Atomic` types, and can represent one or more of these types at a time. They correspond to a vertical bar in a doc comment.

``` php
new Union([new TNamedObject('Foo\\Bar\\SomeClass')]); // equivalent to Foo\Bar\SomeClass in docblock
new Union([new TString(), new TInt()]); // equivalent to string|int in docblock
```

## Atomic types

Primitive types like floats, integers and strings, plus arrays, and classes. You can find all of these in [`src/Psalm/Types/Atomic`](https://github.com/vimeo/psalm/tree/master/src/Psalm/Type/Atomic).

Note that all non-abstract classes in this folder are valid types. They are all prefixed by 'T'.

The classes are as follows:

### Misc

`TVoid` - denotes the `void` type, normally just used to annotate a function/method that returns nothing

`TNull` - denotes the `null` type

`TNever` - denotes the `no-return`/`never-return` type for functions that never return, either throwing an exception or terminating (like the builtin `exit()`). Also used for union types that can have no possible types (impossible intersections for example).  Empty arrays `[]` have the type `array<never, never>`.

`TMixed` - denotes the `mixed` type, used when you don’t know the type of an expression.

`TNonEmptyMixed `- as above, but not empty. Generated for `$x` inside the `if` statement `if ($x) {...}` when `$x` is `mixed` outside.

`TEmptyMixed` - as above, but empty. Generated for `$x` inside the `if` statement `if (!$x) {...}` when `$x` is `mixed` outside.

`TIterable` - denotes the [`iterable` type](https://www.php.net/manual/en/language.types.iterable.php) (which can also result from an `is_iterable` check).

`TResource` - denotes the `resource` type (e.g. a file handle).

`TClosedResource` - denotes the `resource` type that has been closed (e.g. a file handle through `fclose()`).

`TAssertionFalsy` - Represents any value reduced to false when computed in boolean context. This is used for assertions

`TConditional` - Internal representation of a conditional return type in phpdoc. For example ($param1 is int ? int : string)

`TIntMask` - Represents the type that is the result of a bitmask combination of its parameters. `int-mask<1, 2, 4>` corresponds to `1|2|3|4|5|6|7`

`TIntMaskOf` - as above, but used with a reference to constants in code `int-mask-of<MyClass::CLASS_CONSTANT_*>` will corresponds to `1|2|3|4|5|6|7` if there are three constant 1, 2 and 4

`TKeyOf` - Represents an offset of an array (e.g. `key-of<MyClass::CLASS_CONSTANT>`).

`TValueOf` - Represents a value of an array or enum (e.g. `value-of<MyClass::CLASS_CONSTANT>`).

`TTemplateIndexedAccess` - To be documented

`TTemplateKeyOf` - Represents the type used when using TKeyOf when the type of the array is a template

`TTemplateValueOf` - Represents the type used when using TValueOf when the type of the array or enum is a template

`TPropertiesOf` - Represents properties and their types of a class as a keyed array (e.g. `properties-of<MyClass>`)

`TTemplatePropertiesOf` - Represents the type used when using TPropertiesOf when type of the class is a template

`TTypeAlias` - To be documented

### Scalar supertype

`TScalar` - denotes the `scalar` super type (which can also result from an `is_scalar` check). This type encompasses `float`, `int`, `bool` and `string`.

`TEmptyScalar` - denotes a `scalar` type that is also empty.

`TNonEmptyScalar` - denotes a `scalar` type that is also non-empty.

### Numeric supertype

`TNumeric` - denotes the `numeric` type (which can also result from an `is_numeric` check).

`TEmptyNumeric` - denotes the `numeric` type that's also empty (which can also result from an `is_numeric` and `empty` check).

### Scalar types

All scalar types have literal versions e.g. `int` vs `int(5)`.

#### Ints

`TInt` - denotes the `int` type, where the exact value is unknown.

`TLiteralInt` - is used to represent an integer value where the exact numeric value is known.

`TIntRange` - allows to describe an int with bounded values (ie. `int<1, 5>`).

#### Floats

`TFloat` - denotes the `float` type, where the exact value is unknown.

`TLiteralFloat` - is used to represent a floating point value where the exact numeric value is known.

#### Bools

`TBool`, `TFalse`, `TTrue`

`TBool` - denotes the `bool` type where the exact value is unknown.

`TFalse` - denotes the `false` value type

`TTrue` - denotes the `true` value type

``` php
/** @return string|false    false when string is empty, first char of the parameter otherwise */
function firstChar(string $s) { return empty($s) ? false : $s[0]; }
```

Here, the function may never return true, but if you had to replace false with bool, Psalm would have to consider true as a possible return value. With narrower type it's able to report meaningless code like this (https://psalm.dev/r/037291351d):

``` php
$first = firstChar("sdf");
if (true === $first) {
  echo "This is actually dead code";
}
```

#### Strings

`TString` - denotes the `string` type, where the exact value is unknown.

`TNonEmptyString` - denotes a string, that is also non-empty

`TNumericString` - denotes a string that's also a numeric value e.g. `"5"`. It can result from `is_string($s) && is_numeric($s)`.

`TLiteralString` - is used to represent a string whose value is known.

`TClassString` - denotes the `class-string` type, used to describe a string representing a valid PHP class. The parent type from which the classes descend may or may not be specified in the constructor.

`TLiteralClassString` - denotes a specific class string, generated by expressions like `A::class`.

`TTraitString` - denotes the `trait-string` type, used to describe a string representing a valid PHP trait.

`TDependentGetClass` - Represents a string whose value is a fully-qualified class found by get_class($var)

`TDependentGetDebugType` - Represents a string whose value is that of a type found by get_debug_type($var)

`TDependentGetType` - Represents a string whose value is that of a type found by gettype($var)

`TCallableString` - denotes the `callable-string` type, used to represent an unknown string that is also `callable`.

`TSqlSelectString` - this is a special type, specifically for consumption by plugins.

`TLowercaseString` - denotes a string where every character is lowercased. (which can also result from a `strtolower` call).

`TNonEmptyLowercaseString` - denotes a non-empty-string where every character is lowercased. (which can also result from a `strtolower` call).

`TSingleLetter` - denotes a string that has a length of 1

#### Scalar class constants

`TScalarClassConstant` - denotes a class constant whose value might not yet be known.

#### Array key supertype

`TArrayKey` - denotes the `array-key` type, used for something that could be the offset of an `array`.

### Arrays

`TArray` - denotes a simple array of the form `array<TKey, TValue>`. It expects an array with two elements, both union types.

`TNonEmptyArray` - as above, but denotes an array known to be non-empty.

`TKeyedArray` represents an 'object-like array' - an array with known keys.

``` php
$x = ["a" => 1, "b" => 2]; // is TKeyedArray, array{a: int, b: int}
$y = rand(0, 1) ? ["a" => null] : ["a" => 1, "b" => "b"]; // is TKeyedArray with optional keys/values, array{a: ?int, b?: string}
```

This type is also used to represent lists (instead of the now-deprecated `TList` type).  

Note that not all associative arrays are considered object-like. If the keys are not known, the array is treated as a mapping between two types.

``` php
$a = [];
foreach (range(1,1) as $_) $a[(string)rand(0,1)] = rand(0,1); // array<string,int>
```

`TCallableKeyedArray` - denotes an object-like array that is _also_ `callable`.

`TClassStringMap` - Represents an array where the type of each value is a function of its string key value

### Callables & closures

`TCallable` - denotes the `callable` type. Can result from an `is_callable` check.
`TClosure` - denotes a `Closure` type.

`TCallable` and `TClosure` can optionally be defined with parameters and return types, too

### Object supertypes

`TObject` - denotes the `object` type

`TObjectWithProperties` - an object with specified member variables e.g. `object{foo:int, bar:string}`.

### Object types

`TNamedObject` - denotes an object type where the type of the object is known e.g. `Exception`, `Throwable`, `Foo\Bar`

`TGenericObject` - denotes an object type that has generic parameters e.g. `ArrayObject<string, Foo\Bar>`

`TCallableObject` - denotes an object that is also `callable` (i.e. it has `__invoke` defined).

`TAnonymousClassInstance` - Denotes an anonymous class (i.e. `new class{}`) with potential methods

### Template

`TTemplateParam` - denotes a template parameter that has been previously specified in a `@template` tag.

`TTemplateParamClass` - denotes a `class-string` corresponding to a template parameter previously specified in a `@template` tag.

## Creating type object instances

There are two ways of creating the object instances which describe a given type. They can be created directly using new, or created declaratively from a doc string. Normally, you'd want to use the second option. However, understanding the structure of this data will help you understand types passed into a plugin.

Note that these classes do sometimes change, so `Type::parseString` is always going to be the more robust option.

### Creating type object instances directly

The following example constructs types representing a string, a floating-point number, and a class called 'Foo\Bar\SomeClass'.

``` php
new TLiteralString('A text string')
new TLiteralFloat(3.142)
new TNamedObject('Foo\Bar\SomeClass')
```

Types within Psalm are always wrapped in a union as a convenience feature. Almost anywhere you may expect a type, you can get a union as well (property types, return types, argument types, etc). So wrapping a single atomic type (like TInt) in a union container allows to uniformly handle that type elsewhere, without repetitive checks like this:

``` php
if ($type instanceof Union)
   foreach ($types->getTypes() as $atomic)
      handleAtomic($atomic);
else handleAtomic($type);

// with union container it becomes
foreach ($types->getTypes() as $atomic)
   handleAtomic($atomic);
```

Also, union trees are always shallow, because Psalm will flatten union of unions into a single-level union `((A|B)|(C|D) => A|B|C|D)`.

More complex types can be constructed as follows. The following represents an associative array with 3 keys. Psalm calls these 'object-like arrays', and represents them with the 'TKeyedArray' class.


``` php
        new Union([
            TKeyedArray::make([
                'key_1' => new Union([new TString()]),
                'key_2' => new Union([new TInt()]),
                'key_3' => new Union([new TBool()])])]);
```

The Type object includes some static helper methods, which automatically wrap the type in a Union. Thus this can be written more tersely:

``` php
new Union([
    new Type\Atomic\TKeyedArray([
        'first' => Type::getInt(),
        'second' => Type::getString()])]);
```

You can also use `Type::getInt(5)` to generate a union type corresponding to the literal int value 5.


### Creating type object instances from doc string types

Another way of creating these instances is to use the class `Psalm\Type` which includes a static method `parseString`. You may pass any doc string type description to this, and it will return the corresponding object representation.

``` php
\Psalm\Type::parseString('int|null');
```

You can find how Psalm would represent a given type as objects, by specifying the type as an input to this function, and calling `var_dump` on the result.

---

--- METRICS ---
- Files Extracted: 369
- Estimated Token Budget: ~125900 tokens
- Canonical Reference: https://codewiki.google/github.com/vimeo/psalm
