Skip to content

Commit 803f353

Browse files
phpstan-botclaude
authored andcommitted
Add CLAUDE.md with project documentation
Comprehensive guide covering project overview, PHP version constraints (7.4+), repository structure, how rules and configuration work, development commands, testing patterns, CI pipeline, and coding standards. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 38c26a9 commit 803f353

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

CLAUDE.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# CLAUDE.md
2+
3+
## Project Overview
4+
5+
**phpstan/phpstan-strict-rules** is a PHPStan extension that provides extra strict and opinionated rules for PHP static analysis. While PHPStan focuses on finding bugs, this package enforces strictly and strongly typed code with no loose casting, targeting developers who want additional safety through defensive programming.
6+
7+
The package is installed via Composer (`phpstan/phpstan-strict-rules`) and integrates with PHPStan through the `rules.neon` configuration file.
8+
9+
## PHP Version Support
10+
11+
This repository supports **PHP 7.4+** (unlike phpstan-src which is PHP 8.1+ with PHAR downgrade). The `composer.json` sets `"php": "^7.4 || ^8.0"` and the platform is pinned to PHP 7.4.6 for dependency resolution.
12+
13+
**Do not use PHP 8.0+ syntax** (named arguments, match expressions, union type hints in signatures, etc.) in the source code. Property declarations with types (e.g., `private Type $prop;`) are allowed as they are PHP 7.4 syntax.
14+
15+
## Repository Structure
16+
17+
```
18+
├── src/Rules/ # Rule implementations (PSR-4: PHPStan\)
19+
│ ├── BooleansInConditions/ # Rules requiring booleans in conditions
20+
│ ├── Cast/ # Useless cast detection
21+
│ ├── Classes/ # Parent constructor call requirements
22+
│ ├── DisallowedConstructs/ # Bans on empty(), loose comparison, backtick, etc.
23+
│ ├── ForLoop/ # Variable overwrite detection in for loops
24+
│ ├── ForeachLoop/ # Variable overwrite detection in foreach loops
25+
│ ├── Functions/ # Strict array_filter, closure $this usage
26+
│ ├── Methods/ # Illegal constructor calls, method name casing
27+
│ ├── Operators/ # Numeric operand enforcement in arithmetic
28+
│ ├── StrictCalls/ # Strict function calls, static method enforcement
29+
│ ├── SwitchConditions/ # Type matching in switch/case
30+
│ └── VariableVariables/ # Disallow variable variables
31+
├── tests/Rules/ # Tests mirroring src/ structure
32+
│ └── */data/ # PHP test fixture files
33+
├── tests/Levels/ # Integration tests for PHPStan levels
34+
├── rules.neon # Main extension config (parameters, services, conditional tags)
35+
├── phpstan.neon # Self-analysis config (used for analysing this repo)
36+
├── phpunit.xml # PHPUnit configuration
37+
├── Makefile # Build commands
38+
└── composer.json # Package definition
39+
```
40+
41+
## How Rules Work
42+
43+
Each rule implements `PHPStan\Rules\Rule<TNodeType>`:
44+
45+
1. **`getNodeType(): string`** — Returns the PHP-Parser AST node class this rule inspects.
46+
2. **`processNode(Node $node, Scope $scope): array`** — Analyses the node and returns an array of errors (empty array = no errors).
47+
48+
Errors are built with `RuleErrorBuilder::message('...')->identifier('error.id')->build()`.
49+
50+
Helper classes (`BooleanRuleHelper`, `OperatorRuleHelper`) contain shared validation logic and are injected via constructor.
51+
52+
Rules are registered as services in `rules.neon` and toggled via `conditionalTags` tied to `strictRules.*` parameters.
53+
54+
## Configuration System
55+
56+
`rules.neon` serves two purposes:
57+
58+
1. **Sets stricter PHPStan defaults** (lines 1-16): Parameters like `checkDynamicProperties`, `reportMaybesInMethodSignatures`, `checkFunctionNameCase`, etc. These are always active when the extension is installed.
59+
2. **Registers toggleable custom rules** (lines 17+): Each rule can be individually enabled/disabled through `strictRules.*` parameters using `conditionalTags`.
60+
61+
The `allRules` parameter (default: `true`) controls all rules at once. Individual parameters override it.
62+
63+
## Development Commands
64+
65+
All commands are in the `Makefile`:
66+
67+
```bash
68+
make check # Run all checks (lint + cs + tests + phpstan)
69+
make lint # PHP syntax check via parallel-lint
70+
make cs # Coding standards check (requires build-cs, see cs-install)
71+
make cs-install # Clone and install phpstan/build-cs
72+
make cs-fix # Auto-fix coding standard violations
73+
make tests # Run PHPUnit tests
74+
make phpstan # Run PHPStan self-analysis at level 8
75+
```
76+
77+
To set up the project:
78+
```bash
79+
composer install
80+
```
81+
82+
For coding standards (separate tooling):
83+
```bash
84+
make cs-install
85+
make cs
86+
```
87+
88+
## Testing
89+
90+
Tests use PHPUnit 9.6 and PHPStan's `RuleTestCase` base class.
91+
92+
### Test structure
93+
94+
- Each rule has a corresponding `*Test.php` in `tests/Rules/` mirroring the `src/Rules/` directory structure.
95+
- Test data files (PHP fixtures) live in `tests/Rules/*/data/`.
96+
- Integration-level tests are in `tests/Levels/`.
97+
98+
### Writing a test
99+
100+
```php
101+
/**
102+
* @extends RuleTestCase<YourRule>
103+
*/
104+
class YourRuleTest extends RuleTestCase
105+
{
106+
protected function getRule(): Rule
107+
{
108+
return new YourRule(/* dependencies */);
109+
}
110+
111+
public function testRule(): void
112+
{
113+
$this->analyse([__DIR__ . '/data/fixture.php'], [
114+
[
115+
'Expected error message text.',
116+
42, // line number
117+
],
118+
]);
119+
}
120+
}
121+
```
122+
123+
For rules with dependencies, use `self::getContainer()->getByType(ClassName::class)` to get services from PHPStan's DI container.
124+
125+
Some tests conditionally check based on `PHP_VERSION_ID` for version-specific behavior.
126+
127+
### Running tests
128+
129+
```bash
130+
make tests # Run all tests
131+
php vendor/bin/phpunit # Run all tests directly
132+
php vendor/bin/phpunit tests/Rules/Cast/ # Run tests in a directory
133+
php vendor/bin/phpunit --filter UselessCastRuleTest # Run a specific test
134+
```
135+
136+
## CI Pipeline
137+
138+
GitHub Actions (`.github/workflows/build.yml`) runs on PRs and pushes to `2.0.x`:
139+
140+
- **Lint**: PHP syntax check on PHP 7.4–8.4
141+
- **Coding Standard**: phpcs via phpstan/build-cs (2.x branch)
142+
- **Tests**: PHPUnit on PHP 7.4–8.4, both lowest and highest dependencies
143+
- **Static Analysis**: PHPStan at level 8 on PHP 7.4–8.4, both lowest and highest dependencies
144+
145+
The default branch is `2.0.x`.
146+
147+
## Coding Standards
148+
149+
- Uses phpstan/build-cs (2.x branch) with phpcs for coding standards.
150+
- **Tabs for indentation** in PHP, XML, and Neon files (see `.editorconfig`).
151+
- Spaces for YAML files.
152+
- `declare(strict_types = 1)` at the top of every PHP file.
153+
- PSR-4 autoloading: `PHPStan\` namespace maps to `src/`.
154+
- Import functions explicitly (`use function sprintf;`), not via `\sprintf()`.

0 commit comments

Comments
 (0)