phpyh/psalm-tester
Run and compare Psalm static analysis results across versions and configurations. Handy for CI, regression checks, and testing plugin or baseline changes, with simple CLI tooling to spot new issues or verify improvements quickly.
Installation
composer require --dev phpyh/psalm-tester
Ensure psalm is installed globally or via Composer (composer require --dev vimeo/psalm).
Basic Configuration
Add to composer.json under extra:
"psalm": {
"bin": "vendor/bin/psalm",
"config": "psalm.xml"
}
Or configure via PsalmTester::setPsalmConfig() in PHP.
First Use Case Run a simple test to verify Psalm’s output:
use Phyh\PsalmTester\PsalmTester;
test('Psalm passes with no errors', function () {
$result = PsalmTester::run();
$result->assertNoErrors();
});
tests/PsalmTest.php (if creating custom assertions)config/psalm.xml (Psalm’s core config)phpunit.xml (if integrating with PHPUnit)Use in GitHub Actions/GitLab CI to enforce Psalm compliance:
# .github/workflows/psalm.yml
jobs:
psalm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: composer install
- run: vendor/bin/phpunit --testdox-html --filter "Psalm"
Assert expected errors for new/changed code:
test('New method triggers expected Psalm error', function () {
$result = PsalmTester::run(['--init']);
$result->assertErrorContains('ClassMyClass has a method with no return type');
});
Compare against a snapshot of "known good" output:
test('Psalm output matches baseline', function () {
$result = PsalmTester::run();
$result->assertOutputMatchesFile(__DIR__.'/baseline.txt');
});
PsalmTester::setPsalmConfig(app()->basePath('psalm.xml'));
use Illuminate\Console\Command;
use Phyh\PsalmTester\PsalmTester;
class RunPsalmCommand extends Command {
protected $signature = 'psalm:run';
public function handle() {
$result = PsalmTester::run();
$this->line($result->getOutput());
if ($result->hasErrors()) {
$this->error('Psalm found issues!');
}
}
}
pest or phpunit: Use PsalmTester in feature tests to validate type safety.PsalmTester::run(['--threads', '--init', 'src/']);
PsalmTesterResult for project-specific checks:
$result->assertErrorCount(3); // Custom assertion
False Positives in CI
vendor/ paths).--init to regenerate cache or mock vendor/ in tests:
PsalmTester::run(['--init', '--no-cache']);
Slow Test Suites
--threads:
vendor/bin/psalm --threads=4 --init
Baseline Drift
vendor/bin/psalm --init > baseline.txt
Laravel-Specific Quirks
Illuminate\Support\Collection).ignoreErrors in psalm.xml:
<error-level>Errors</error-level>
<ignoreErrors>
<error>MixedAssignment</error>
<error>MixedReturnType</error>
</ignoreErrors>
PsalmTester::run(['--debug']);
PsalmTester::run(['--no-cache', '--init']);
PsalmTester::run(['src/MyClass.php']);
Custom Error Parsing
Override PsalmTesterResult::parseOutput() to handle project-specific Psalm formats.
Pre/Post-Run Hooks
Extend PsalmTester to run setup/teardown:
PsalmTester::beforeRun(function () {
// Copy config files, etc.
});
Git Pre-Commit Hooks
Use PsalmTester to block commits with Psalm errors:
# .git/hooks/pre-commit
vendor/bin/phpunit --filter "Psalm" || exit 1
Visual Studio Code Integration
Add a task to run Psalm via PsalmTester in tasks.json:
{
"label": "Run Psalm",
"type": "process",
"command": "vendor/bin/phpunit --filter Psalm",
"problemMatcher": ["$phpunit"]
}
How can I help you explore Laravel packages today?