Static Analysis (PHPStan & Psalm)
7 questions found
What is static analysis, and how do tools like PHPStan and Psalm help catch bugs in PHP code before it is even run?
Beginner
Static analysis is the process of examining source code without actually executing it, looking for patterns that indicate likely bugs, such as calling a method that does not exist, passing the wrong data type to a function, or referencing a variable that was never defined, and tools like PHPStan and Psalm scan an entire codebase this way, catching many categories of mistakes that would otherwise only be discovered later at runtime, potentially in production, helping developers fix issues much earlier and with much greater confidence in their code's correctness.
vendor/bin/phpstan analyse src/
Real-world example
A development team runs PHPStan against their entire codebase before every deployment, automatically catching a typo in a method name that would have otherwise only surfaced as an error once a specific rarely used feature was actually triggered by a real user.
Common follow-ups: Can static analysis catch every possible bug in an application?;How does static analysis differ from unit testing in terms of what kinds of issues each one catches?
Type Declarations & Strict Types;Unit Testing with PHPUnit
What are analysis levels in PHPStan, and why would a project typically start at a lower level before gradually increasing strictness?
Beginner
PHPStan organizes its checks into numbered levels, starting from a lenient level zero that only catches the most obvious, clear cut errors, up to a very strict maximum level that enforces comprehensive type correctness throughout the entire codebase, and a project with a large amount of existing code that was not originally written with static analysis in mind typically starts at a lower level to avoid being immediately overwhelmed by a huge number of reported issues, then gradually increases the level over time as the team fixes existing issues and becomes more comfortable with stricter type discipline.
# phpstan.neon
parameters:
level: 5
paths:
- src
Real-world example
A team inheriting a large, older codebase configures PHPStan to start at level two, gradually raising it to level six over several months as they progressively fix the issues uncovered at each successive level.
Common follow-ups: What kinds of checks are enforced only at the very highest PHPStan levels?;How can a team gradually adopt static analysis without it blocking every single existing pull request immediately?
Type Declarations & Strict Types;Deployment & Hosting for PHP Applications
How do type declarations and PHPDoc comments help a static analysis tool understand your code more accurately and catch more potential issues?
Intermediate
Static analysis tools rely heavily on type information to understand what kind of value a variable, parameter, or return value is expected to hold, and while PHP's native type declarations provide some of this information directly, PHPDoc comments let you specify more precise details that PHP's type system alone cannot express, such as the exact shape of an array or the specific type of objects contained within a collection, giving the static analysis tool much more information to work with when checking whether your code is actually using those values correctly.
/**
* @param array<int, string> $names
* @return string[]
*/
function formatNames(array $names): array {
return array_map('strtoupper', $names);
}
Real-world example
A team documents the precise shape of arrays returned from their data access layer using detailed PHPDoc annotations, allowing PHPStan to catch a mistake where a developer later tried to access a key that does not actually exist within that documented array shape.
Common follow-ups: What is the difference between a native PHP type declaration and a PHPDoc based type annotation?;How does static analysis handle situations where a type genuinely cannot be determined with full certainty?
Type Declarations & Strict Types;Basics & Types
What is a baseline file in PHPStan, and how does it help a team adopt static analysis on an existing project without needing to fix every single issue immediately?
Intermediate
A baseline file records every currently existing issue that static analysis finds in a codebase at a specific point in time, effectively telling the tool to ignore those specific already known issues going forward, while still reporting any brand new issue introduced afterward, which lets a team immediately start enforcing static analysis on all new code being written without first needing to pause everything and fix potentially hundreds of preexisting issues throughout an older, large codebase all at once.
vendor/bin/phpstan analyse --generate-baseline
Real-world example
A team adopting PHPStan on a five year old codebase generates a baseline capturing the several hundred existing issues, then configures their continuous integration pipeline to fail only on any brand new issue introduced in future pull requests, letting them adopt the tool immediately without a massive one time cleanup effort.
Common follow-ups: How should a team periodically work down the size of an existing baseline file over time?;What happens to the baseline file when a genuinely fixed issue is later removed from the actual code?
Unit Testing with PHPUnit;Deployment & Hosting for PHP Applications
How does Psalm's concept of taint analysis help detect potential security vulnerabilities like SQL injection or cross site scripting during static analysis?
Intermediate
Taint analysis tracks how data flows through an application starting from an untrusted source, such as user submitted form input, following that data through every function call and variable assignment it passes through, and flags a potential security issue if that tainted, untrusted data ever reaches a sensitive destination, called a sink, such as being directly concatenated into a raw SQL query or echoed directly into HTML output, without first being properly sanitized or escaped somewhere along that path.
vendor/bin/psalm --taint-analysis
Real-world example
A security conscious team runs Psalm's taint analysis feature as part of their continuous integration pipeline, automatically catching a case where a developer accidentally passed raw, unescaped user input directly into an HTML template without first sanitizing it.
Common follow-ups: Can taint analysis realistically catch every possible security vulnerability in an application?;How does a team properly mark a specific data sanitization function as safely removing the taint from a value?
Security;Form Handling & Validation
How can integrating a static analysis tool into a continuous integration pipeline help enforce consistent code quality across an entire team, and what are common strategies for managing false positives?
Advanced
Running static analysis automatically as part of a continuous integration pipeline ensures that every single pull request is checked consistently before it can be merged, preventing new type related bugs or risky patterns from ever reaching the main codebase regardless of which individual developer wrote the code, and since static analysis tools occasionally produce false positives, meaning they flag something as a potential issue that is actually perfectly safe in context, teams typically manage this by using targeted inline suppression comments for specific, well understood exceptions rather than disabling entire categories of checks globally.
/** @psalm-suppress PossiblyNullArgument */
$result = processValue($maybeNullValue);
Real-world example
An engineering team configures their continuous integration pipeline to automatically run PHPStan on every pull request, blocking the merge button entirely until any newly introduced static analysis issues are either fixed or explicitly and specifically suppressed with a documented justification.
Common follow-ups: What is the risk of overusing suppression comments throughout a codebase?;How should a team decide on an appropriate strictness level to enforce specifically within continuous integration versus during local development?
Unit Testing with PHPUnit;Deployment & Hosting for PHP Applications
How do custom PHPStan or Psalm rules and extensions let a team enforce their own project specific coding standards and catch domain specific mistakes beyond the tool's built in checks?
Advanced
Beyond the extensive built in checks that PHPStan and Psalm already provide, both tools support writing custom rules or extensions tailored to a specific project's own conventions and common mistakes, such as flagging direct calls to a deprecated internal helper function that should no longer be used, enforcing that a certain type of object is always constructed through a designated factory method rather than directly, or ensuring a specific naming convention is consistently followed across an entire team, letting the tool encode institutional knowledge that generic, general purpose checks alone could never capture.
final class NoDirectDatabaseQueryRule implements Rule {
public function processNode(Node $node, Scope $scope): array {
// custom rule logic here
}
}
Real-world example
A large engineering organization writes a custom PHPStan rule that flags any code directly instantiating a database connection outside of their designated repository classes, enforcing a consistent architectural pattern automatically across every single pull request submitted by any team.
Common follow-ups: How much ongoing maintenance effort is typically required to keep a set of custom static analysis rules up to date?;Are there community maintained rule sets available for popular frameworks like Laravel or Symfony?
Design Patterns in PHP;Unit Testing with PHPUnit