Expert patterns for modernizing PHP applications to PHP 8.x with type safety, PSR/PER compliance, static analysis tools, and Symfony best practices.
This is an Agent Skill following the open standard originally developed by Anthropic and released for cross-platform use.
Supported Platforms:
- Claude Code (Anthropic)
- Cursor
- GitHub Copilot
- Other skills-compatible AI agents
Skills are portable packages of procedural knowledge that work across any AI agent supporting the Agent Skills specification.
- PHP 8.x Features: Constructor property promotion, readonly properties and classes, named arguments, enums and match expressions, attributes (replacing annotations), union and intersection types, nullsafe operator
- Static Analysis Tools: PHPStan (level 9+), PHPat (architecture testing), Rector (automated refactoring), PHP-CS-Fixer (coding style)
- PSR/PER Compliance: Enforces all active PHP-FIG standards (PSR-1, 3, 4, 6, 7, 11, 12, 13, 14, 15, 16, 17, 18, 20) and PER Coding Style
- Type Safety Patterns: DTOs and Value Objects over arrays, generic collection typing via PHPDoc, strict typing enforcement, PHPStan level 10 compliance, runtime type validation
- Symfony Integration: Dependency injection patterns, service configuration (YAML to PHP), event dispatcher and PSR-14, form handling modernization, security component updates
/plugin marketplace add netresearch/claude-code-marketplaceDownload the latest release and extract to ~/.claude/skills/php-modernization-skill/
composer require netresearch/agent-php-modernization-skillRequires: netresearch/composer-agent-skill-plugin
This skill is automatically triggered when:
- Modernizing PHP codebases to PHP 8.1/8.2/8.3/8.4/8.5
- Implementing type safety and strict typing
- Setting up static analysis tools (PHPStan, PHPat, Rector, PHP-CS-Fixer)
- Ensuring PSR/PER compliance
- Adopting Symfony best practices
- Achieving PHPStan level 9+/10 compliance
- Upgrading from older PHP versions
- Implementing generic collection patterns
Example queries:
- "Modernize this PHP class to PHP 8.2"
- "Add strict type safety with PHPStan level 10"
- "Set up PHPat architecture tests"
- "Configure Rector for PHP 8.3 upgrade"
- "Ensure this code follows PSR standards"
- "Convert YAML service configuration to PHP"
- "Implement readonly class with constructor promotion"
- "Make this HTTP client PSR-18 compliant"
php-modernization-skill/
├── SKILL.md # Skill metadata and core patterns
├── references/
│ ├── static-analysis-tools.md # PHPStan, PHPat, Rector, PHP-CS-Fixer
│ ├── psr-per-compliance.md # Active PSR and PER standards
│ ├── php8-features.md # PHP 8.0-8.5 feature adoption patterns
│ ├── type-safety.md # Type system maximization strategies
│ ├── symfony-patterns.md # Modern Symfony architecture
│ ├── phpstan-compliance.md # PHPStan configuration details
│ └── migration-strategies.md # Version upgrade planning
└── scripts/
└── verify-php-project.sh # Verification script
All modern PHP projects must use these tools:
| Tool | Purpose | Requirement |
|---|---|---|
| PHPStan | Type checking, bug detection | Level 9 minimum, level 10 recommended |
| PHPat | Architecture testing | Required for projects with defined architecture |
| Rector | Automated refactoring | Required for modernization |
| PHP-CS-Fixer | Coding style | Required with @PER-CS |
All modern PHP code must follow active PHP-FIG standards:
| Standard | Purpose | Requirement |
|---|---|---|
| PSR-1 | Basic Coding | Required |
| PSR-4 | Autoloading | Required |
| PER Coding Style | Coding Style | Required (supersedes PSR-12) |
| PSR-3 | Logger | Use when logging |
| PSR-6/16 | Cache | Use when caching |
| PSR-7/17/18 | HTTP | Use for HTTP clients |
| PSR-11 | Container | Use for DI containers |
| PSR-14 | Events | Use for event dispatching |
| PSR-15 | Middleware | Use for HTTP middleware |
| PSR-20 | Clock | Use for time-dependent code |
Source of truth: https://www.php-fig.org/psr/ and https://www.php-fig.org/per/
- Constructor property promotion
- Readonly properties and classes
- Named arguments
- Enums and match expressions
- Attributes (replacing annotations)
- Union and intersection types
- Nullsafe operator
- DTOs and Value Objects over arrays (see below)
- Generic collection typing via PHPDoc
- Strict typing enforcement
- PHPStan level 9+/10 compliance
- Runtime type validation
Never pass or return raw arrays for structured data. Use typed objects instead:
| Instead of | Use |
|---|---|
array $userData |
UserDTO $user |
array{email: string, name: string} |
readonly class UserDTO |
array $config |
readonly class Config or Value Object |
array $request |
RequestDTO::fromRequest($request) |
return ['success' => true, 'data' => $x] |
return new ResultDTO($x) |
Why:
- Arrays lack type safety at runtime
- No IDE autocompletion for array keys
- PHPStan cannot verify array shapes across boundaries
- Refactoring arrays is error-prone
Pattern:
// ❌ Bad: Array passing
public function createUser(array $data): array
// ✅ Good: DTO pattern
public function createUser(CreateUserDTO $dto): UserDTOSee references/request-dtos.md for complete patterns including Request DTOs, Command/Query DTOs, and Value Objects
Never use string/integer constants or arrays for fixed sets of values. Use PHP 8.1+ backed enums instead:
| Instead of | Use |
|---|---|
const STATUS_DRAFT = 'draft' |
enum Status: string { case Draft = 'draft'; } |
['draft', 'published', 'archived'] |
Status::cases() |
string $status parameter |
Status $status parameter |
switch ($status) |
match($status) with enum |
Why enums are required:
- Compile-time type checking (invalid values caught before runtime)
- IDE autocompletion for all valid values
- Exhaustive
match()enforcement (compiler ensures all cases handled) - Methods encapsulate related logic (labels, colors, validation)
- Self-documenting API with clear valid options
Pattern:
// ❌ Bad: String constants
class Order {
public const STATUS_DRAFT = 'draft';
public const STATUS_PENDING = 'pending';
public const STATUS_COMPLETED = 'completed';
public function setStatus(string $status): void // Any string accepted!
}
// ✅ Good: Backed enum
enum OrderStatus: string {
case Draft = 'draft';
case Pending = 'pending';
case Completed = 'completed';
public function label(): string {
return match($this) {
self::Draft => 'Draft Order',
self::Pending => 'Awaiting Payment',
self::Completed => 'Order Complete',
};
}
}
class Order {
public function setStatus(OrderStatus $status): void // Only valid statuses!
}See references/php8-features.md for complete enum patterns including methods, validation, and database integration.
- Dependency injection patterns
- Service configuration (YAML to PHP)
- Event dispatcher and PSR-14
- Form handling modernization
- Security component updates
- PHPStan at level 9+ (level 10 for new projects)
- PHPat architecture tests for layer dependencies
- Rector with
LevelSetList::UP_TO_PHP_83andSetList::CODE_QUALITY - PHP-CS-Fixer with
@PER-CSruleset
- Update composer.json PHP requirement
- Enable strict_types in all files
- Replace annotations with attributes
- Convert to constructor property promotion
- Use readonly where applicable
- Replace switch with match expressions
- Replace string/int constants with backed enums
- Use enums for all status, type, and option values
- Configure PSR-4 autoloading in composer.json
- Enforce PER Coding Style via PHP-CS-Fixer (
@PER-CS) - Type-hint against PSR interfaces (not implementations)
- Use PSR-3 for logging
- Use PSR-14 for event dispatching
- Use PSR-18/17 for HTTP clients
- Use PSR-20 for time-dependent code
- Add return types to all methods
- Add parameter types to all methods
- Use union types instead of mixed
- Replace array parameters with DTOs
- Replace array returns with typed objects
- Use Value Objects for domain concepts (Email, Money, etc.)
- Use backed enums for all fixed value sets (status, type, options)
- Add @template annotations for generics
- Remove @var annotations where inferrable
- security-audit-skill: Security patterns for PHP applications
- typo3-testing-skill: PHPUnit patterns (applicable to any PHP project)
MIT License - See LICENSE for details.
Developed and maintained by Netresearch DTT GmbH.
Made with love for Open Source by Netresearch