PHP Modernization Skill
Expert patterns for modernizing PHP applications to PHP 8.x with type safety, PSR / PER-CS compliance, static-analysis tooling, and Symfony-grade architecture. The skill ships an agent contract — a small set of executable tools that emit machine-readable verification reports, archetype profiles, and fix-loop transcripts.
Compatibility
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.
Features
- Agent contract: a Python verifier (
verify_php_project.py), orchestrator (modernize_loop.py), and cheap profiler (introspect.py). stable structured output (JSON with schema_version 1.0.0, SARIF 2.1.0, or JUnit XML), archetype detection, and machine-readable agent_actions[] recommendations downstream agents can act on without re-reading the prose references.
- Hard guardrails: five binding refusal cases enforced in
SKILL.md (no readonly on Doctrine entities, no Rector without --dry-run, baseline shrink-not-delete, no blanket final on mock targets, no editing generated files).
- PHP 8.x feature coverage: 8.0–8.3 baseline, dedicated 8.4 reference (released 2024-11: property hooks, asymmetric visibility, lazy objects,
array_find / array_any / array_all), and dedicated 8.5 reference (released 2025-11: pipe |>, array_first / array_last, #[\NoDiscard]).
- Static-analysis stack: PHPStan (level 9+, level 10 recommended), PHPat (architecture testing), Rector (automated refactoring), PHP-CS-Fixer (
@PER-CS), Infection (mutation testing in PR-diff mode), composer audit.
- Type-safety patterns: DTOs and Value Objects over arrays, generic collection typing via PHPDoc, strict typing everywhere, immutability boundaries (
readonly vs. property hooks vs. classic mutation).
- Framework edges: dedicated references for Doctrine 2.x/3.x edges, API Platform resource separation, and PSR-15 middleware architecture.
- PSR / PER-CS compliance: PSR-1, 3, 4, 6, 7, 11, 13, 14, 15, 16, 17, 18, 20 plus PER Coding Style. PSR-12 superseded by PER-CS.
- Project-archetype detection:
generic-composer, typo3-extension, symfony-app, monorepo-package. The verifier and orchestrator branch on archetype.
- Regression suite: synthetic fixtures plus golden-output snapshots guard the verifier from contract drift.
Agent Contract
The skill follows a four-step loop. Cheap commands first; expensive analysis only when needed.
- Discover — read
SKILL.md, then profile the project.
- Drill — narrow to one finding at a time when more than three things fail.
- Apply — preview every fix in
--mode dry-run before mutating files.
- References — load
references/<topic>.md only when the long-form rationale is needed.
One-line invocations
# Cheap first-touch profile (no subprocesses except `php --version`)
uv run skills/php-modernization/scripts/introspect.py --root .
# Full mechanical verification with agent_actions[]
uv run skills/php-modernization/scripts/verify_php_project.py --root . --format json --summary
# One checkpoint at a time
uv run skills/php-modernization/scripts/verify_php_project.py --root . --check PM-02
# Orchestrated fix preview (no mutations; use --confirm to apply)
uv run skills/php-modernization/scripts/modernize_loop.py --mode dry-run
uv is the recommended runner for the Python tools (it resolves the PEP 723 inline dependencies automatically). The Bash wrapper transparently falls back to python3 if uv is not installed.
Output formats
verify_php_project.py accepts --format json | sarif | junit. JSON is the canonical contract (see schemas/verification-result.schema.json). SARIF 2.1.0 plugs into the GitHub Security → Code scanning tab. JUnit XML is convenient for CI dashboards. Checkpoint IDs (PM-XX) are stable forever — never renumbered.
Hard Guardrails
The five guardrails below are binding. The agent must refuse rather than violate them.
- Never apply
readonly to Doctrine entities or mapped-superclasses (embeddables are a nuanced case, ORM 3.x dependent — see references/doctrine-modernization-edges.md).
- Never run Rector without
--dry-run first.
- Never raise the PHPStan level without regenerating + committing the baseline in the same change. Shrink, never delete.
- Never apply blanket
final to mock targets or extension points without confirmation.
- Never edit
@generated files or files under var/cache/, vendor/, node_modules/, .Build/.