Write strict PHP without the boilerplate.
Every .xphp file automatically gets <?php declare(strict_types=1); — you never have to type it again.
// src/Services/UserService.xphp — just start writing
class UserService
{
public function getUser(int $id): User
{
return User::find($id); // strict types enforced, no boilerplate needed
}
}composer require roastrofficial-ctrl/xphpThat's it. After composer install, the package:
- Registers the
xphp://stream wrapper - Registers an SPL autoloader for
.xphpfiles, reading your PSR-4 mappings automatically - Writes IDE config for PhpStorm and VS Code
- Patches
psalm.xml/phpstan.neonif they exist
Rename any .php file to .xphp and drop the opening boilerplate. The autoloader picks up your existing PSR-4 mappings from composer.json, so App\Services\UserService maps to src/Services/UserService.xphp exactly as you'd expect.
Files can start with raw code, or keep <?php if your editor needs it for syntax highlighting — both work:
// Option A — raw (no opening tag needed)
class MyClass { }
// Option B — keep the tag, skip the declare
<?php
class MyClass { }# Lint a single file
vendor/bin/xphp-lint src/Services/UserService.xphp
# Lint an entire directory recursively
vendor/bin/xphp-lint src/
# Use in CI
vendor/bin/xphp-lint src/ && echo "All good"xphp-lint automatically detects and runs any of these tools if they're installed in your project:
| Linter | Docs | What it checks |
|---|---|---|
php -l |
N/A | Syntax errors (always runs) |
| pint | laravel/pint | Code style & formatting |
| phpstan | phpstan.org | Static type analysis |
| psalm | psalm.dev | Static type analysis + runtime errors |
Zero configuration. If you have vendor/bin/pint in your project, it runs automatically on xphp-lint — with the .xphp file header transparently injected so all checks work correctly.
With only syntax checking (default):
$ vendor/bin/xphp-lint src/
✓ src/Services/UserService.xphp (php)
✓ src/Models/User.xphp (php)With pint + syntax checking:
$ vendor/bin/xphp-lint src/
✓ src/Services/UserService.xphp (php + pint)
✓ src/Models/User.xphp (php + pint)With pint, phpstan, and syntax checking:
$ vendor/bin/xphp-lint src/
✓ src/Services/UserService.xphp (php + pint + phpstan)
✓ src/Models/User.xphp (php + pint + phpstan)If a file fails any check, all failing checks are reported:
$ vendor/bin/xphp-lint src/BadFile.xphp
✗ src/BadFile.xphp
[php] Parse error: syntax error, unexpected end of file
[pint] 5 style issues found
The lint command integrates seamlessly with your existing tooling — just install pint, phpstan, or psalm normally, and xphp-lint will pick them up automatically.
IDE config is written automatically after composer install. To re-run it manually:
vendor/bin/xphp-ide # Write/update config
vendor/bin/xphp-ide --force # Overwrite existing config
vendor/bin/xphp-ide --dry-run # Preview what would be written| File | Purpose |
|---|---|
.idea/fileTypes/xphp.xml |
PhpStorm: treat .xphp as PHP |
.vscode/settings.json |
VS Code/Cursor + Intelephense: treat .xphp as PHP |
psalm.xml |
Psalm: scan .xphp files (if Psalm is installed) |
phpstan.neon |
PHPStan: scan .xphp files (if PHPStan is installed) |
These files are safe to commit to version control.
When PHP's autoloader encounters App\Services\UserService, it:
- Resolves the class to
src/Services/UserService.xphp - Loads the file via
include 'xphp://...' - The
xphp://stream wrapper intercepts, prepends the strict types header - PHP compiles it — strict types enforced, no boilerplate ever written
The stream wrapper approach is used internally by Laravel, Psalm, and others. It carries no meaningful performance overhead.
The header is injected on the same line as <?php (or as a single prepended line), so line numbers stay accurate for Xdebug.
PHPStan and Psalm will scan .xphp files after composer install. Since the strict types declaration is injected at runtime, not present in the source, you may want to tell your analyser to assume it globally:
Psalm: add useStrictTypes="true" to <psalm> in psalm.xml.
PHPStan: this is the default behaviour in strict mode (--level=max).
Both tools are automatically integrated into vendor/bin/xphp-lint if installed:
# If phpstan is installed, it runs automatically
vendor/bin/xphp-lint src/
# Output: ✓ src/MyClass.xphp (php + phpstan)
# Same with psalm
vendor/bin/xphp-lint src/
# Output: ✓ src/MyClass.xphp (php + psalm)No additional setup needed — the lint command handles header injection and transparently passes .xphp files to your analyser.
MIT