A custom .xphp file extension that automatically injects <?php and declare(strict_types=1) — write strict PHP without the boilerplate.
Requires
- php: >=8.1
This package is not auto-updated.
Last update: 2026-03-22 13:52:31 UTC
README
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 } }
Installation
composer require roastrofficial-ctrl/xphp
That'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
Usage
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 { }
Linting
# 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"
Auto-detection of linters
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.
Examples
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
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
What gets 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.
How it works
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.
Xdebug & line numbers
The header is injected on the same line as <?php (or as a single prepended line), so line numbers stay accurate for Xdebug.
Static analysis
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).
Running with lint command
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.
License
MIT