What you'll learn
Let tools find entire classes of mistakes before runtime. PSR-12 formatting removes style debate, static analysis checks data flow, and small behavior-protected refactors improve structure without changing results.
By the end of this lesson, you'll be able to:
- Configure a consistent style check
- Add precise types for static analysis
- Refactor in small test-protected steps
Core mental model
Professional PHP is less about memorizing APIs and more about choosing a clear boundary for each responsibility. Use this table as a decision guide while reading the examples.
| Concept | What it protects | Decision rule |
|---|---|---|
| Static analysis | Impossible-path detection | Raise strictness gradually and keep the baseline shrinking. |
| Formatter | Mechanical consistency | Automate style instead of reviewing it manually. |
| Refactor | Structural improvement | Preserve externally observable behavior. |
Professional workflow
Build the feature in small, verifiable steps. Each step leaves the system in a state you can test.
- Describe the quality gate boundary: its inputs, outputs, invariants, and expected failures.
- Implement the smallest happy path behind an explicit contract.
- Add validation and translate low-level failures into language the caller understands.
- Exercise the boundary with realistic data, then inspect output, logs, and resource cleanup.
- Refactor only after behavior is protected by a repeatable check.
Make the boundary visible
Guided code lab
Teach the analyzer collection shapes
Generics in PHPDoc let tools prove each item supports the operations used in the loop.
<?php
final class CourseCatalog
{
/** @param list<Course> $courses @return list<string> */
public function publishedTitles(array $courses): array
{
return array_values(array_map(
static fn (Course $course): string => $course->title(),
array_filter($courses, static fn (Course $course): bool => $course->isPublished()),
));
}
}Run one local quality command
The pipeline is explicit, reproducible, and fails before unverified code is merged.
{
"scripts": {
"format:check": "php-cs-fixer fix --dry-run --diff",
"analyse": "phpstan analyse src tests --level=max",
"test": "phpunit",
"check": ["@format:check", "@analyse", "@test"]
}
}Production practice
Contract
Quality configuration belongs in version control and the same command runs locally and in CI.
Verification
Protect behavior with tests before refactoring; make one transformation, then run the smallest relevant check.
Operations
Pin tool versions, cache safely in CI, and review automated upgrade diffs like any other code.
Common failure mode
Independent workshop
Take an untyped legacy service to maximum practical analysis strictness while preserving its public API.
Your finished workshop must include:
- Characterization tests
- Typed DTOs and collection shapes
- Green style, analysis, and test command with no new baseline
Definition of done
Recap & quick check
Key takeaways
- Automation makes quality repeatable.
- Precise types improve both tools and design.
- Refactoring changes structure, not behavior.
- Quality gates stop regressions before merge.
Quick check
1. What does a refactor intentionally preserve?
2. Why format automatically?
3. What should happen to a static-analysis baseline?
Keep the workshop: later phases deliberately build on these boundaries, so today's small example can become part of your portfolio architecture.