This repository contains a hands-on PHPStan workshop built around a small Laravel codebase plus a set of focused examples.
0-Workshop/Challenge— your assignment: fix the PHPStan typing issues (see below)0-Workshop/Solution— the reference solution1-6-*— small, slide-aligned example snippets (each directory corresponds to a topic from the slides)bin/— helper scripts so you don’t need PHP/Composer installed locally (Docker only)
You’ll do all workshop commands through
./bin/*scripts.
Docker (Compose) is required.
You can find the related slides here
# 1) Clone
git clone <this-repo>
cd <this-repo>
# 2) Install dependencies + prepare databases
./bin/composer setup
# 3) Confirm everything is healthy (solution + examples)
./bin/composer phpstan
# 4) Now work on the assignment and verify your work
./bin/composer verify- Warm-up / reference material: browse 1-6-* directories and follow along with the presentation.
- Main assignment: work in 0-Workshop/Challenge until ./bin/composer verify is green.
- Compare with the solution: if you get stuck, inspect 0-Workshop/Solution (but try not to copy).
Main workshop app
-
0-Workshop/Challenge
Laravel app + domain code with intentionally incomplete PHPStan typing. Your goal is to improve types without “papering over” errors (no ignore-spamming). -
0-Workshop/Solution
The same app, but with the intended typing in place.
These directories are small, self-contained code samples that illustrate slide concepts:
1-Aliases/— type aliases (intro scaffold)2-Asserts/— assertion helpers (@phpstan-assert*) example3-Generics/— generics (intro scaffold)4-Stubs/— stubs example (see SubscriptionClient.stub)5-Community-Extensions/— community extensions (intro scaffold)6-Custom-Extensions/— a custom PHPStan rule example (BoundaryRule.php)
The phpstan.neon config includes the solution + these example directories so you can run analysis over everything in one go.
All commands below run inside Docker.
Run this before you start.
``./bin/composer setup
What it does (high-level):
- ensures sqlite DB files exist for both apps
- installs Composer dependencies
- links vendor/ into the workshop directories (so everything is consistent)
- runs fresh migrations and seeds for both Solution and Challenge
./bin/composer phpstan
This runs PHPStan using phpstan.neon, which covers:
0-Workshop/Solution/...1-6-*topic example directories
Use this to confirm your environment is correct and to inspect “good” typing patterns.
./bin/composer verify
This runs PHPStan using phpstan-challenge.neon, which targets:
- 0-Workshop/Challenge/Application
- 0-Workshop/Challenge/Domain
- 0-Workshop/Challenge/Framework/Database
- plus related Laravel folders
This is the command you’ll use repeatedly while working on the assignment.
You can boot the containers with:
./bin/start
The docker compose file exposes:
- Solution: http://localhost:9061/api/v1/product
- Challenge: http://localhost:9062/api/v1/product
Drop into a shell inside the container:
./bin/attach
# or, for a one-off shell:
./bin/sh
Run artisan commands (executed against the solution container entrypoint):
./bin/artisan route:list
./bin/artisan migrate:fresh --seed
Run Composer in the container (generic wrapper):
./bin/composer install
./bin/composer phpstan
./bin/composer verify
Goal: make ./bin/composer verify pass by improving PHPStan typing in 0-Workshop/Challenge—without weakening analysis.
This challenge is designed to mirror real-world “why is PHPStan upset?” situations:
- Missing/incorrect type aliases for array shapes
- Missing generic templates on interfaces
- Implementations that don’t tell PHPStan what generic parameters they fulfill
Work only in:
- 0-Workshop/Challenge/**
…and make ./bin/composer verify succeed.
These are examples of categories of improvements that PHPStan typically needs:
- Add array shape types (@phpstan-type FooArray array{...})
- Add parameter/return type annotations to “shape-based” factories like fromArray()
- Add templates/generics to interfaces (e.g. @template TQuery of Query, @template TResult)
- Add @implements on concrete handlers to bind generic params
If you want to compare, check how the same concepts are expressed in:
- 0-Workshop/Solution/... (reference implementation)
- 2-Asserts/phoneParser.php (assertion typing)
- 4-Stubs/SubscriptionClient.stub (telling PHPStan about external APIs)
- 6-Custom-Extensions/PHPStan/BoundaryRule.php (custom rule structure)
The scripts support both docker compose and docker-compose. Install Docker Desktop or the Docker Engine + Compose plugin.
The scripts pass your host UID/GID into the container. If file permissions look off, try:
./bin/start --build
Re-run:
./bin/composer setup
That will refresh vendor links and reset both sqlite DBs/migrations.
./bin/composer phpstan uses phpstan.neon
./bin/composer verify uses phpstan-challenge.neon
Open those files to see which paths are included.
Happy type hunting! 👀