Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* text
.* export-ignore
composer.lock text -diff
phpunit.* export-ignore
tests export-ignore
phpunit.xml export-ignore
pint.json export-ignore
39 changes: 39 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Summary

<!-- Provide a brief description of what this PR does and why it's needed -->

## Type of Change

- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
- [ ] ✨ New feature (non-breaking change which adds functionality)
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] 📚 Documentation update
- [ ] ⚡ Performance improvement
- [ ] ♻️ Code refactoring
- [ ] 🧪 Test improvements
- [ ] 🔧 Chore (build process, dependencies, etc.)

## Related Issues

<!-- Link to related issues using GitHub keywords -->

<!-- Ignore if not applicable -->

Closes #<!-- issue number -->

## Pre-Submission Checklist

<!-- Verify all items before submitting this PR -->

### Code Quality

- [ ] **PHPStan analysis passes**
- [ ] **Coding standards pass**
- [ ] **All tests pass**
- [ ] **No debug code** (var_dump, error_log, etc.) left in production code
- [ ] **No commented-out code** unless specifically needed for reference
- [ ] **Documentation updated** for any new features or changed behavior
- [ ] **New tests** have been added for new functionality
- [ ] **All existing tests** continue to pass

**📖 Read the full contributing guidelines: [CONTRIBUTING.md](/.github/CONTRIBUTING.md)**
28 changes: 28 additions & 0 deletions .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: PHPStan

on:
pull_request:
push:
branches:
- main

jobs:
phpstan:
name: Static Analysis
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none

- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Run PHPStan
run: composer test:phpstan
31 changes: 31 additions & 0 deletions .github/workflows/pint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: fix code styling

on:
pull_request:
push:
branches:
- main

jobs:
lint:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
tools: composer:v2, laravel/pint
extensions: json, dom, curl, libxml, mbstring
coverage: none

- name: Run Pint
run: pint

- name: Commit linted files
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: 'chore: fix code styling'
38 changes: 38 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Tests

on:
pull_request:
push:
branches:
- main

jobs:
tests:
name: PHP ${{ matrix.php }}
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
php:
- '7.4'
- '8.0'
- '8.1'
- '8.2'
- '8.3'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none

- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Run tests
run: vendor/bin/phpunit
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
composer.lock
vendor/
tests/_support/_generated

# Dev tools
.buildpath
*.iml
.project
.idea/
.vscode/

# Tests
.phpunit.cache

.DS_Store
DOCKER_ENV
Dockerfile-*
output.log
docker_tag

CLAUDE.md
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Change Log

All notable changes to this project will be documented in this file. This project adhere to the [Semantic Versioning](http://semver.org/) standard.

## [0.1.0] 2025-12-11

* Feature - Initial release of PHPStan Container Extensions.

[0.1.0]: https://github.com/dpanta94/phpstan-containers/releases/tag/0.1.0
69 changes: 69 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# PHPStan Container Extensions

[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-239922)](https://github.com/phpstan/phpstan)

PHPStan extensions for dependency injection containers. Provides dynamic return type resolution so PHPStan understands that `$container->get(Foo::class)` returns `Foo`.

## Supported Containers

- [StellarWP Container Contract](https://github.com/stellarwp/container-contract) (`StellarWP\ContainerContract\ContainerInterface`)
- [PSR-11 Container](https://www.php-fig.org/psr/psr-11/) (`Psr\Container\ContainerInterface`)

## Requirements

- PHP 7.4 or higher
- PHPStan 2.0 or higher

## Installation

```bash
composer require --dev dpanta94/phpstan-containers
```

If you use [phpstan/extension-installer](https://github.com/phpstan/extension-installer), you're all set!

### Manual Installation

If you don't use the extension installer, add the extension to your `phpstan.neon`:

```neon
includes:
- vendor/dpanta94/phpstan-containers/extension.neon
```

## Usage

Once installed, PHPStan will automatically understand container return types:

```php
use Psr\Container\ContainerInterface;

class MyService {
public function __construct(private ContainerInterface $container) {}

public function doSomething(): void {
// PHPStan knows $logger is an instance of Logger
$logger = $this->container->get(Logger::class);
$logger->info('Hello world');

// PHPStan knows $mailer is an instance of MailerInterface
$mailer = $this->container->get(MailerInterface::class);
$mailer->send($message);
}
}
```

The extension resolves types when:

- The argument to `get()` is a class-string constant (e.g., `Foo::class`)
- The class or interface exists in the codebase

When using string service IDs (e.g., `$container->get('mailer')`), the extension falls back to the default `mixed` return type.

## License

MIT

## Credits

This package is inspired by [Phil Nelson](https://github.com/phil-nelson)'s [phpstan-container-extension](https://packagist.org/packages/phil-nelson/phpstan-container-extension).
53 changes: 53 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "dpanta94/phpstan-containers",
"description": "PHPStan extensions for Containers",
"license": "MIT",
"type": "phpstan-extension",
"keywords": [
"static analysis",
"code analysis",
"code analyze",
"container",
"dependency injection",
"phpstan",
"psr-11"
],
"require": {
"php": "^7.4 || ^8.0",
"phpstan/phpstan": "^2.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^9.5 || ^10.0",
"psr/container": "^1.0 || ^2.0",
"stellarwp/container-contract": "^1.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"DPanta\\PHPStan\\Containers\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"DPanta\\PHPStan\\Containers\\Tests\\": "tests/",
"DPanta\\PHPStan\\Containers\\Tests\\Data\\": "tests/data/"
}
},
"config": {
"sort-packages": true
},
"extra": {
"phpstan": {
"includes": [
"extension.neon"
]
}
},
"scripts": {
"test": "phpunit",
"test:phpstan": "phpstan analyze"
}
}
9 changes: 9 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
-
class: DPanta\PHPStan\Containers\StellarWpContainerDynamicReturnTypeExtension
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension
-
class: DPanta\PHPStan\Containers\PsrContainerDynamicReturnTypeExtension
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension
7 changes: 7 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon

parameters:
level: max
paths:
- src/
22 changes: 22 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
cacheDirectory=".phpunit.cache"
executionOrder="depends,defects"
beStrictAboutOutputDuringTests="true"
failOnRisky="true"
failOnWarning="true">
<testsuites>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
</testsuites>

<source>
<include>
<directory suffix=".php">src</directory>
</include>
</source>
</phpunit>
7 changes: 7 additions & 0 deletions pint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"preset": "psr12",
"exclude": [
"vendor",
"tests"
]
}
Loading
Loading