---
title: Static Analysis With PHPStan | Shopware Community Hub
description: >-
  Learn how to configure PHPStan for Shopware plugins, fix common issues, and
  integrate PHPStan into your CI/CD pipeline.
canonical_url: 'https://hub.shopware.com/learn/unit/phpstan-static-analysis'
---

# Static Analysis With PHPStan

<LearningObjectives>

- Configure PHPStan with suitable level and extensions for Shopware plugins.
- Understand how to use baselines and gradually increase analysis strictness.
- Integrate PHPStan into CI pipelines for continuous code quality checks.
- Address common type-safety issues, such as generics, nullability, and array shapes.

</LearningObjectives>

# Static Analysis With PHPStan

Static analysis with PHPStan helps you catch bugs before runtime by analyzing your code without executing it.

In this learning unit, you'll learn how to configure PHPStan for Shopware plugins, address common type-safety issues specific to the Shopware ecosystem, and integrate PHPStan into your development workflow for continuous quality improvement.

## Why PHPStan Matters for Shopware Plugins

PHPStan provides several key benefits when developing Shopware plugins:

- **Early Bug Detection**: Catch type errors, undefined methods, and null pointer issues before they reach production.
- **Easier Updates**: Prepare for updates with fixing deprecated code.
- **Better IDE Support**: Proper type annotations improve autocomplete and navigation in your IDE.
- **Documentation**: Type hints serve as inline documentation for your code.
- **Refactoring Confidence**: Safe refactoring knowing PHPStan will catch breaking changes.
- **Code Quality**: Enforces consistent coding standards across your team.

## Configuring and Running PHPStan

### Initial Setup

First, install PHPStan via Composer as dev dependencies:

```bash
composer require --dev phpstan/phpstan
```

It's possible to execute PHPStan without a configuration file, however, creating a `phpstan.neon` file is useful to specify the analysis level, cache paths and so on.

```yaml
parameters:
  level: max  # Use max level if you start completely new (currently level 10)
  paths:
    - src
    - tests
    # You should basically add every directory that contains PHP files
  tmpDir: var/cache/phpstan # optional, would otherwise write in the system tmp directory, which will be lost after a reboot
```

#### Understanding the Rule Levels

PHPStan offers 11 levels (0–10) with increasing strictness.

For detailed information about what each level checks, see the [PHPStan rule levels documentation](https://phpstan.org/user-guide/rule-levels).

**Recommendations:**

- **New plugins**: Use the **maximum level (`level: max`)** from day one.
  Starting with the strictest rules, ensure the highest code quality and prevent accumulating technical debt.
  There is no reason to start out below level 8.

- **Existing plugins**: Use the highest level possible.
  But a reasonable way is to start at **level 8** and generate a baseline for existing errors.
  This allows you to enforce strict standards on new code while gradually fixing legacy issues.

#### Using a Baseline for Existing Code

When you have an existing project and PHPStan is finding errors in your code, you can create a baseline file, so that first only all new code needs to be compliant with PHPStan.

Errors from the baseline are ignored during normal analysis, so you can concentrate on fixing your new changes but gradually fix the existing code.

Execute the following command:

```bash
./vendor/bin/phpstan --generate-baseline
```

This creates a `phpstan-baseline.neon` file with all current errors.
Add it like this to your configuration:

```yaml
includes:
  - phpstan-baseline.neon

parameters:
  # ...
```

For more details on the baseline feature, see the [PHPStan documentation](https://phpstan.org/user-guide/baseline).

#### Additional PHPStan Extensions

In addition to the core PHPStan package, we also use these extensions, which we would like to recommend as well:

- [phpstan-symfony](https://github.com/phpstan/phpstan-symfony): Provides support for Symfony services, controllers and commands.
- [phpstan-deprecation-rules](https://github.com/phpstan/phpstan-deprecation-rules): Detects usage of deprecated code.
- [phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit): Provides support for PHPUnit.
- [phpstan-strict-rules](https://github.com/phpstan/phpstan-strict-rules): Provides additional rules for stricter code checks.
- [rector/type-perfect](https://github.com/rectorphp/type-perfect): More advanced type declaration check.
- [symplify/phpstan-rules](https://github.com/symplify/phpstan-rules): Additional useful rules, which could be enabled individually.
- [phpat/phpat](https://github.com/carlosas/phpat): Framework to easily set up architectural checks.

We created a [common configuration file](https://github.com/shopware/shopware/blob/v6.7.3.0/src/Core/DevOps/StaticAnalyze/PHPStan/common.neon), which we also use for our own plugins, which you can also include in your project.

```yaml
includes:
  - ../../../vendor/shopware/core/DevOps/StaticAnalyze/PHPStan/common.neon # Depending on what your setup looks like, this path might vary

parameters:
  # ...
```

Some PHPStan extensions need special configuration, like the Symfony extension.

```yaml
parameters:
  # ...
  symfony:
    containerXmlPath: ../path/to/var/cache/your_env/Shopware(...)DebugContainer.xml
    consoleApplicationLoader: ../../../src/Core/DevOps/StaticAnalyze/console-application.php # path might vary
```

For the Symfony extension to properly work, you need to link the container XML file generated by Symfony.

You can link to your current cache and environment directory or execute a special bootstrap script, which starts the Shopware kernel to create a container just for analyzing your code.

If your plugin is installed via composer, you can use this [bootstrap script](https://github.com/shopware/shopware/blob/v6.7.3.0/src/Core/DevOps/StaticAnalyze/phpstan-bootstrap.php).

Configure it like this:

```yaml
parameters:
  # ...
  bootstrapFiles:
    - ../../../src/Core/DevOps/StaticAnalyze/phpstan-bootstrap.php # path might vary
```

### Running PHPStan

To execute the PHPStan analysis, run the following command:

```bash
./vendor/bin/phpstan analyze -v 
```

The output can look like this:

```bash
Note: Using configuration file /home/test/www/6.7/phpstan.neon.dist.
9010/9010 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% 2 mins

[OK] No errors

Elapsed time: 2 minutes 20 seconds
Used memory: 10.13 GB
```

The numbers before the progress bar indicate the number of files analyzed. This example is from the Shopware platform repository, where PHPStan checked 9010 files.

## Integrating PHPStan into CI/CD

You get the most out of PHPStan if you integrate it into your CI/CD pipeline to check for errors before merging code.

- Set up your CI/CD pipeline in your favorite environment as usual.
- Ensure that Composer installs all dependencies including dev dependencies.
- Make sure a Symfony DI container is built if you want to use the Symfony extension.
- After that, run PHPStan as shown above.

PHPStan also supports different output formats. For more information, see the [PHPStan documentation](https://phpstan.org/user-guide/output-format).

### Reducing the Baseline Over Time

If you set up PHPStan with a baseline, you should work on reducing the number of errors over time. In Shopware, we are using [danger.php](https://github.com/shyim/danger-php) to remind us about that.

The `Danger.php` file is set up as a CI job that could be used to execute checks on the changed files.

Create a `.danger.php` file in your plugin root, where you can define the following:

```php
return (new Config())
    ->useRule(function (Context $context): void {
        $filesWithIgnoredErrors = [];
        $platformPullRequest = $context->platform->pullRequest;
        
        $phpstanBaseline = $platformPullRequest->getFile('phpstan-baseline.neon')->getContent();
        $fileNames = $platformPullRequest->getFiles()->map(fn (File $f) => $f->name);
        
        foreach ($fileNames as $fileName) {
            if (str_contains($phpstanBaseline, 'path: ' . $fileName)) {
                $filesWithIgnoredErrors[] = $fileName;
            }
        }

        if ($filesWithIgnoredErrors) {
            $context->failure(
                'Some files you touched in your MR contain ignored PHPStan errors. Please be nice and fix all ignored errors for the following files:<br>'
                . implode('<br>', $filesWithIgnoredErrors)
            );
        }
    })
;
```

So now every time someone touches a file in your plugin, `danger.php` will check if there are any ignored errors of this file in the baseline.

If this is the case, a failure will be reported with the files that should be fixed. With this approach you can reduce the number of ignored errors over time.

---

If you want to dive deeper into PHPStan, here are some useful resources:

- [Common PHPStan issues in Shopware](https://developer.shopware.com/docs/resources/guidelines/troubleshooting/phpstan.html)
- [Writing PHP code for PHPStan](https://phpstan.org/writing-php-code/phpdocs-basics)

## Summary

In this learning unit, you have learned:

- How to configure PHPStan for Shopware plugins.
- How to address common type-safety issues specific to the Shopware ecosystem.
- How to integrate PHPStan into your development workflow for continuous quality improvement.

With this knowledge, you can use static analysis as a reliable safety net to keep your Shopware plugins maintainable and robust over time.

---

**Congratulations!** You have successfully completed this learning unit and with it the entire **Backend Development Intermediate** learning path.

This was not a lightweight journey. By working with topics such as the DAL, APIs, translations, events and dependency injection, checkout cart logic, and through advanced testing strategies, you have closed important gaps and significantly strengthened your backend development skill set.

You can be proud of the progress you have made! Well done!
