Static analysis: ESLint, PHPStan, mypy — Architecture & Trade‑offs — Practical Guide (Jun 19, 2026)
body { font-family: Arial, sans-serif; line-height: 1.6; margin: 2em; max-width: 900px; }
h2, h3 { margin-top: 1.5em; }
pre { background: #f4f4f4; padding: 1em; overflow-x: auto; }
code { font-family: Consolas, monospace; }
p.audience { font-style: italic; color: #555; }
p.social { margin-top: 3em; font-size: 0.9em; colour: #333; }
ul { margin-left: 1.2em; }
Static analysis: ESLint, PHPStan, mypy — Architecture & Trade‑offs
Level: Intermediate
As of June 2026, static analysis tools have become an integral part of software engineering workflows across multiple languages. Tools like ESLint for JavaScript/TypeScript, PHPStan for PHP, and mypy for Python help catch bugs early, enforce style consistency, and improve code quality without running the application.
This article provides a practical overview of these three tools, focusing on their architectural design, trade-offs, and integration approaches, aimed at intermediate engineers who want to make informed decisions on adopting or refining static analysis processes.
Prerequisites
To fully benefit from this article, you should have:
- Intermediate programming experience with one or more of JavaScript/TypeScript, PHP, or Python.
- Basic familiarity with command-line interfaces and package managers (npm/yarn, Composer, pip).
- Understanding of static typing concepts and linting principles.
- Access to a development environment with these languages installed.
Static analysis tools overview and architecture
Each tool implements static analysis in a way that reflects both the target language ecosystem and typical developer needs.
ESLint (JavaScript/TypeScript)
ESLint (version 8.x as of mid-2026) is primarily a linting utility focused on enforcing coding standards and preventing common mistakes. It parses source files via a fast, robust JavaScript parser (espree by default), producing an Abstract Syntax Tree (AST). ESLint runs configured rules that inspect the AST patterns to report issues. It also supports autofixing certain problems.
Extension through plugins allows ESLint to support TypeScript via @typescript-eslint/parser, and integrate stylistic rules, security checks, and complexity metrics.
PHPStan (PHP)
PHPStan (version 1.12+ recommended) is a static analysis tool that focuses on type inference and code correctness without running the code. It uses PHP’s parser to build internal representations of code elements and performs flow-sensitive type analysis. PHPStan excels at discovering type-related errors, unused methods, unreachable code, and misuses of APIs.
It is highly configurable, supporting multiple analysis levels (0–8) that increase strictness, with higher levels requiring more explicit type annotations in PHPDoc or native types (PHP 7.4+).
mypy (Python)
mypy (version 1.3+ stable release) is built for gradual static typing of Python programs. It leverages the typed_ast parser variant to read Python source code and combined with inline type hints (PEP 484) performs static type checking. mypy helps find mismatches, missing attributes, possible type errors, and code inconsistencies.
Given Python’s dynamic nature, mypy supports progressive typing so codebases can adopt static types incrementally. It also offers strictness flags to tune checks.
Hands-on steps: Installing and running each tool
ESLint setup
# Install ESLint globally or locally via npm/yarn
npm install eslint --save-dev
# Initialise configuration (interactive)
npx eslint --init
# Check a directory
npx eslint src/
Sample minimal .eslintrc.json configuration:
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended"],
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "single"]
}
}
PHPStan setup
# Install via Composer globally or per project
composer require --dev phpstan/phpstan
# Initialise a phpstan.neon config manually or minimal example:
echo "includes:n - phpstan-baseline.neon" > phpstan.neon
# Run in level 5 (default 0-8)
vendor/bin/phpstan analyse src --level=5
Minimal phpstan.neon example:
parameters:
level: 5
paths:
- src
memoryLimit: 512M
mypy setup
# Install via pip
pip install mypy
# Run against a file or directory
mypy my_module.py
mypy my_package/
Minimal mypy.ini:
[mypy]
python_version = 3.10
ignore_missing_imports = True
strict = True
Common pitfalls and trade-offs
- Performance and scale: ESLint’s performance is generally fast on typical front-end projects but can slow down if many plugins or heavy type checking via
@typescript-eslintis enabled. PHPStan’s strict levels can significantly increase analysis time on large codebases and require careful tuning of baseline files to exclude legacy issues. mypy may be slower on very large Python projects due to type inference complexity but offers caching to mitigate this. - False positives & false negatives: All tools rely on user annotations or conventions (e.g. PHPDoc, Python type hints, ESLint comments). Insufficient or incorrect annotations may lead to missed issues, while strict rules can sometimes flag correct code (false positives). Managing rule sets and using suppression sparingly is crucial.
- Configuration complexity: ESLint’s plugin ecosystem is vast but can be overwhelming, requiring domain knowledge (React, Node.js, security plugins). PHPStan requires gradual adoption and tuning to avoid noise on mixed-type codebases. mypy can be limiting without enough type hint coverage and occasionally struggles with dynamic Python idioms.
- Integration with CI/CD: All tools support command-line interfaces suitable for pipelines. ESLint and mypy integration is generally simple due to npm and pip ubiquity; PHPStan’s PHP ecosystem demands Composer-based setups and handling autoloaders correctly.
Validation: Ensuring useful results
For effective static analysis adoption, consider:
- Run tools incrementally – start with recommended rule sets or moderate levels.
- Review and triage reported issues with the team — distinguish style vs correctness.
- Automate tool runs on pull requests and enforce minimum passing thresholds.
- Use tool autofix commands carefully to reduce manual fixing (ESLint & mypy’s autofix via
--fixor third-party plug-ins, where supported). - Maintain configuration files in version control to ensure consistent environments.
Checklist / TL;DR
- ESLint: Best for JS/TS code quality, style enforcement, lightweight syntax checks, extensible but can be resource-intensive with many plugins.
- PHPStan: Strong focus on PHP type safety and correctness, strictness levels help with gradual adoption, requires PHPDoc/native types for best results.
- mypy: Brings gradual typing to Python, powerful if types are present, complex dynamic features may reduce recall.
- Install via language-standard package managers (npm, Composer, pip).
- Integrate into editor and CI/CD early to maximise feedback loops.
- Use baseline suppression for legacy technical debt.
- Balance rule strictness to reduce noise and maintain developer productivity.
When to choose one over another?
- Choose ESLint if working in the JavaScript/TypeScript ecosystem where style consistency and quick syntax error catching are priorities.
- Choose PHPStan if your PHP codebase is mature enough to leverage strong typing hints or you want static detection of subtle bugs without runtime costs.
- mypy is best where Python codebases aim to adopt static typing or require stronger guarantees on function signatures and variable usage.
References
- <a href="https://eslint.org/docs/latest/" target="_blank