name: run-checks description: Runs the full composer test suite (phpcs + phpstan + phpunit) and interprets failures for the session-samurai project. Use when the user says 'run tests', 'check code', 'does it pass', 'verify my changes', or before committing. Knows phpcs uses phpcs.xml (PSR-12 with exclusions), phpstan uses phpstan.neon (level: max, src/ only), and phpunit bootstraps via tests/Bootstrap.php with optional TestConfiguration.php. Do NOT use mid-refactor when tests are intentionally broken.
run-checks
Critical
- Never skip a failing tool —
composer testruns phpcs → phpstan → phpunit in sequence and stops on first tool failure. If phpcs fails, phpstan and phpunit do not run. Fix each tool's failures before moving on. - Do not run mid-refactor — only run when the handler implementation is complete and all interfaces are fully implemented.
- TestConfiguration.php must exist —
tests/Bootstrap.phploadstests/TestConfiguration.phpif present, otherwise falls back totests/TestConfiguration.php.dist. Tests that hit real backends (Redis, Memcached, MySQL) require live services at the configured hosts. - phpstan runs at level: max — every type annotation error is fatal. The config is
phpstan.neonat repo root, scanningsrc/only.
Instructions
Run the full suite
composer testThis executes in order:
./vendor/bin/phpcs,./vendor/bin/phpstan analyse,./vendor/bin/phpunit --bootstrap tests/Bootstrap.php tests/src/. Verify: all three tools exit 0 before treating the branch as clean.If phpcs fails — fix PSR-12 violations phpcs checks
src/andtests/againstphpcs.xml(PSR12 base with four exclusions). Active exclusions — these rules are not enforced:Squiz.Functions.MultiLineFunctionDeclaration.BraceSpacingPSR2.Methods.FunctionClosingBrace.SpacingBeforeCloseGeneric.Files.LineLength.TooLong(line length is ignored — do not wrap long lines to fix phpcs)Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine
To check only changed files:
composer phpcs-diff(Equivalent to
git diff --name-only origin/master | xargs ls -d 2>/dev/null | xargs ./vendor/bin/phpcs)Verify:
composer phpcsexits 0 before proceeding to Step 3.If phpstan fails — fix type errors phpstan scans
src/only at level max with these relaxations inphpstan.neon:treatPhpDocTypesAsCertain: falsecheckMissingIterableValueType: false
Common causes in this project:
gc()must declare return typeint|false(PHP 8.0+)read()must declare return typestring(neverstring|false)- Constructor parameter types must match the exact extension class (e.g.,
\Redis,\Memcached,\SQLite3)
Run standalone:
composer phpstanVerify: exits 0 before proceeding to Step 4.
If phpunit fails — diagnose the failure type phpunit is bootstrapped by
tests/Bootstrap.php, which:- Autoloads
vendor/autoload.php - Sets
error_reporting(E_ALL | E_STRICT) - Loads
tests/TestConfiguration.php(or.distfallback) - Adds
src/andtests/to the include path
Run standalone:
composer phpunitSee Step 5 for specific failure causes and fixes. Verify: exits 0 with no failures or errors.
- Autoloads
Interpreting phpunit failures (see Common Issues below for messages)
- Connection refused / backend unreachable: the test needs a live service. Check
tests/TestConfiguration.php.distfor the expected host/port constants (e.g.,TESTS_MEMCACHE_HOST,TESTS_MEMCACHE_PORT). - **
read()returns false instead of ''**: the handler'sread()must return''on miss, notfalseornull`. gc()type mismatch: must returnint|false, notboolorvoid.validateId()returns wrong bool: should returntrueif the key exists in the backend,falseotherwise — not alwaystrue.
- Connection refused / backend unreachable: the test needs a live service. Check
Examples
User says: "Do my changes pass?"
Actions taken:
- Run
composer testfrom the repo root. - phpcs reports a violation in
src/NewBackendSessionHandler.phpline 42:Expected 1 blank line after function; 0 found. - Add the blank line. Re-run
composer phpcs— exits 0. - phpstan reports:
Method read() should return string but returns string|false.Fix: changereturn $result ?: '';toreturn $result === false ? '' : $result;. Re-runcomposer phpstan— exits 0. - phpunit: 1 failure —
testReadasserts''but gotfalse. The fix above already resolves this. Re-runcomposer phpunit— exits 0.
Result: All three tools exit 0. Branch is clean.
User says: "Run tests before I commit"
Actions taken:
composer test— all pass.- Report: "phpcs, phpstan, and phpunit all pass. Safe to commit."
Common Issues
PHP Fatal error: Cannot redeclare ... during phpunit bootstrap
- Cause:
tests/TestConfiguration.phpand.distboth define the same constant without guard. - Fix: All constants in
TestConfiguration.phpmust usedefined('X') || define('X', ...)pattern — never baredefine().
Connection refused or Redis connection failed in RedisSessionHandlerTest
- Cause: phpunit test connects to a hardcoded Redis host. Check
tests/src/RedisSessionHandlerTest.php—setUpBeforeClass()calls$redis->connect(host, port). - Fix: Ensure the Redis service is running at the configured host/port, or skip the test with
$this->markTestSkipped('Redis not available').
Call to undefined method on phpstan level max
- Cause: phpstan level max enforces that method calls on mixed/untyped variables are resolved. Add
@var ClassName $varphpdoc or explicit cast before the call.
phpcs error: A closing tag is not permitted at the end of a PHP file
- Fix: Remove the closing
?>tag from the end of anysrc/ortests/file.
composer test stops after phpcs with exit code 1 but no visible error
- Cause: phpcs found warnings-as-errors or a file in
tests/that's excluded from your mental model but included perphpcs.xml(<file>tests</file>). - Fix: Run
./vendor/bin/phpcs --report=fullfor the complete list with file paths and line numbers.
Allowed memory size exhausted during phpstan
- Fix:
php -d memory_limit=512M ./vendor/bin/phpstan analyse