Skip to content
intermediate Phase 12 · Testing & Quality

Static Analysis Fundamentals

Static analysis vs dynamic analysis, benefits for catching bugs early, PHPStan, Psalm, and PHPMD

45m
0 problems
Topic Progress 0%

Static vs Dynamic Analysis

What is Static Analysis?

Static analysis examines code without executing it. It reads source files and reports potential issues based on rules and type information.

What is Dynamic Analysis?

Dynamic analysis examines code while it runs. Unit tests, integration tests, and profiling are forms of dynamic analysis.

Comparison

Aspect Static Analysis Dynamic Analysis
Runs Without execution During execution
Speed Seconds to minutes Minutes to hours
Coverage All code paths Only tested paths
Findings Type errors, code smells, bugs Runtime errors, behavior bugs
False positives Some Rare
Examples PHPStan, Psalm, PHPMD PHPUnit, integration tests

Why Static Analysis Matters

// This passes dynamic analysis (tests work)
function processOrder(array $data): Order
{
    $order = new Order();
    $order->setTotal($data['total']);
    return $order;
}

// But static analysis catches the bug BEFORE running:
// PHPStan: Property Order::$total does not exist
// (You forgot to define the property)

// Or this:
function getPrice(): float
{
    return 'free'; // PHPStan: Method must return float, string returned
}

Static analysis catches type errors, undefined properties, missing return types, and other issues before you ever run the code.

PHPStan: Type Checking

What is PHPStan?

PHPStan analyzes PHP code for type errors without running it. It catches bugs that type checks would catch if PHP had strict typing everywhere.

Basic Usage

# Install
composer require --dev phpstan/phpstan

# Run
vendor/bin/phpstan analyse src/ --level=6

# With configuration (phpstan.neon)
vendor/bin/phpstan analyse

phpstan.neon Configuration

parameters:
    level: 6                    # 0-9 (9 is strictest)
    paths:
        - app/code/Vendor/Module/Api/
        - app/code/Vendor/Module/Model/
    ignoreErrors:
        - '#Property .* is never assigned#'
    excludePaths:
        - app/code/Vendor/Module/Test/

    # Magento-specific rules
    stubs:
        - etc/phpstan/stubs/*.stub

Level Guide

Level Checks
0 Basic checks (unknown classes, functions)
1 Unknown methods on $this, argument types
2 Unknown magic methods/properties
3 Return types, property types
4 Basic dead code, always true/false checks
5 Checking types of arguments passed to methods
6 Basic dead code checking, always true/false
7 Nullable types, undefined variables
8 Union type handling
9 Strict mode, all checks

Magento-Specific PHPStan

# phpstan.neon for Magento
includes:
    - vendor/magento/magento2-phpstan/extension.neon

parameters:
    level: 6
    paths:
        - app/code/Vendor/
    ignoreErrors:
        - '#Call to an undefined method Magento\\Framework\\App\\Config::getValue#'

The Magento extension adds type stubs for Magento's dynamic methods.

Psalm and PHPMD

Psalm: Gradual Typing

Psalm is similar to PHPStan but focuses on gradual type enforcement:

# Install
composer require --dev vimeo/psalm

# Run
vendor/bin/psalm --config=psalm.xml
<!-- psalm.xml -->
<psalm
    errorLevel="4"
    resolveFromConfigFile="true"
    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"
>
    <projectFiles>
        <directory name="app/code/Vendor/Module"/>
        <ignoreFiles>
            <directory name="vendor"/>
        </ignoreFiles>
    </projectFiles>
</psalm>

Psalm's unique feature: type assertions and suppressed issues:

/** @psalm-suppress InvalidReturnType */
public function risky(): mixed
{
    // Psalm won't report this return type issue
}

PHPMD: Mess Detector

PHPMD detects code smells and bad practices:

# Install
composer require --dev phpmd/phpmd

# Run
vendor/bin/phpmd app/code/Vendor/Module/ text rulesets/codesize.xml,rulesets/unusedcode.xml

PHPMD Rulesets:

Ruleset Detects
codesize Long methods, too many parameters
unusedcode Unused variables, unused private methods
cleanCode Duplicate code, overly complex expressions
naming Short variables, long class names
design Too many fields, deep inheritance
<!-- phpmd.xml -->
<ruleset name="Magento Rules"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_1_0_0.xsd">
    <description>Custom rules for Magento</description>
    <rule ref="rulesets/codesize.xml">
        <properties>
            <property name="maximum-method-complexity" value="15"/>
            <property name="maximum-method-length" value="50"/>
            <property name="maximum-parameters" value="5"/>
        </properties>
    </rule>
    <rule ref="rulesets/unusedcode.xml"/>
</ruleset>

All Three Together

# In CI pipeline
vendor/bin/phpstan analyse src/ --level=6
vendor/bin/psalm --config=psalm.xml
vendor/bin/phpmd src/ text phpmd.xml

Quiz

1. What is the key difference between static and dynamic analysis?

Question 1 options

2. PHPStan level 6 checks for:

Question 2 options

3. PHPMD detects:

Question 3 options

Flashcards

Question

Static vs Dynamic analysis?

Answer

Static: without execution (PHPStan). Dynamic: during execution (PHPUnit).

Question

PHPStan levels?

Answer

0-9. Higher = stricter. 6 is recommended starting point.

Question

What does PHPMD detect?

Answer

Code smells: long methods, unused code, duplicate code, deep inheritance

Question

Why use static analysis?

Answer

Catch bugs at write-time before running code, faster feedback loop

Revision Notes

Key Takeaways

  • 1. Static analysis: examines code without executing it (type errors, code smells)
  • 2. Dynamic analysis: examines code during execution (tests, profiling)
  • 3. PHPStan: type checking, levels 0-9, level 6 is recommended
  • 4. Psalm: gradual typing with type assertions and suppressions
  • 5. PHPMD: code smells (long methods, unused code, duplicate code)
  • 6. All three should run in CI pipeline for quality gates

Interview Tips

  • Explain why static analysis complements (not replaces) unit testing
  • Recommend PHPStan level 6 as starting point for Magento
  • Discuss trade-offs: false positives vs catching real bugs

Cheat Sheet

Static Analysis: without execution
Dynamic Analysis: during execution

PHPStan:  composer require --dev phpstan/phpstan
          vendor/bin/phpstan analyse src/ --level=6

Psalm:    composer require --dev vimeo/psalm
          vendor/bin/psalm --config=psalm.xml

PHPMD:    composer require --dev phpmd/phpmd
          vendor/bin/phpmd src/ text phpmd.xml

All three → CI pipeline quality gates