PHPStan
Enhanced static analysis for Yii2 applications with PHPStan
Precise type inference, dynamic method resolution, and comprehensive property reflection
Features
Section titled “Features”Installation
Section titled “Installation”composer require --dev yii2-extensions/phpstan:^0.5Quick start
Section titled “Quick start”Create config/phpstan.php with an analysis-only description of your application:
<?php
declare(strict_types=1);
return [ 'params' => ['adminEmail' => 'admin@example.com'], 'components' => [ 'db' => ['class' => yii\db\Connection::class], ],];Create phpstan.neon in the project root, choosing paths that exist in your application:
includes: - vendor/yii2-extensions/phpstan/extension.neon
parameters: level: 5 paths: - models yii2: config_path: config/phpstan.phpRun PHPStan:
vendor/bin/phpstan analyseType inference examples
Section titled “Type inference examples”The snippets below assume an app\models\Article model with id and title property tags and a published()
query scope. The usage guide describes the analysis configuration for the components, params and
behaviors shown here.
Active Record
Section titled “Active Record”Yii supplies generic types for findOne(), findAll(), relations and the standard query methods. This extension
adds row shapes from model @property tags and precise getAttribute() types:
use app\models\Article;
$article = Article::findOne(1); // Article|null$articles = Article::findAll(['title' => 'Yii']); // array<Article>$query = Article::find()->where(['id' => 1]); // ArticleQuery&ActiveQuery<Article>$published = Article::find()->published()->one(); // Article|null$rows = Article::find()->asArray()->all(); // array<array{id: int, title: string}>
if ($article !== null) { $title = $article->getAttribute('title'); // string}A custom query without generic PHPDoc, such as one generated by Gii, is bound to the model at the find() call site.
Use static or $this scope return types to preserve that binding. Row shapes include inherited property tags;
relation and read-only keys are optional and need guards such as ??. See query limitations
when a query is reached through a typed parameter or a widened relation getter.
Application components
Section titled “Application components”Yii::$app uses phpstan.application_type, which defaults to yii\web\Application. Component classes come from
the analysis configuration:
$view = Yii::$app->exampleView; // yii\web\View$typed = Yii::$app->get('typedView'); // yii\web\View$untyped = Yii::$app->get('untypedView'); // object$request = Yii::$app->request; // yii\web\RequestClass names, class-key arrays, object instances and factories with a single class return type can provide precise
types. An untyped factory yields object; adding an accurate return type makes the result specific. Core components
configured without a class keep the application’s annotated property type.
The built-in user: identityClass mapping also supplies the configured identity class to yii\web\User’s generic
parameter. Its identity property remains nullable. See generic components
and the separate console application configuration.
Application params
Section titled “Application params”Params values become an array shape, including nested arrays and keys containing dots or other punctuation:
$email = Yii::$app->params['adminEmail']; // string$maxItems = Yii::$app->params['maxItems']; // int$enabled = Yii::$app->params['nested']['enabled']; // boolScalars are widened to their types rather than retained as literal values. The same shape applies to inherited
module params, including $this->module->params in a controller. With no configured params, the type stays array.
Behaviors
Section titled “Behaviors”The analysis-only behaviors map exposes members from attached behavior classes. In the example,
TaggedComponent is mapped to TagBehavior; the application must also attach that behavior at runtime:
use app\behaviors\TagBehavior;use app\components\TaggedComponent;
$component = new TaggedComponent();
$component->attachBehavior('tag', new TagBehavior());
$label = $component->label; // string$summary = $component->summarize(); // stringProperties and methods are resolved from the behavior’s native members and PHPDoc. See behavior configuration.
Dependency injection
Section titled “Dependency injection”Container service definitions and aliases are resolved by their IDs:
$view = Yii::$container->get('view.alias'); // yii\web\View$shared = Yii::$container->get('sharedView'); // yii\web\ViewThe example config maps view.alias to view.real and gives sharedView a typed factory. An unresolved definition
keeps the result as object. Container factories, invocable objects and aliases have distinct rules; see
definition forms.
Header collection
Section titled “Header collection”$headers = new yii\web\HeaderCollection();
$host = $headers->get('Host'); // string|null$ids = $headers->get('X-Request-ID', [], false); // array<string>$requestId = $headers->get('X-Request-ID', 'default'); // stringA non-null default removes null from the return type. The $first argument selects a single value or an array.
Logger messages
Section titled “Logger messages”Logger and target message buffers have tuple types without local stubs or PHPDoc overrides:
foreach ((new yii\log\Logger())->messages as $message) { $level = $message[1]; // int $category = $message[2]; // string $timestamp = $message[3]; // float $memory = $message[5] ?? null; // int|null}
$empty = yii\log\Target::filterMessages([]); // array{}Payload types follow the installed Yii version. Filtering preserves the input key and tuple types while allowing an empty result. See the logger examples.
Service locator
Section titled “Service locator”A service locator resolves configured component IDs, while container-only IDs belong to the container:
$view = Yii::$app->get('exampleView'); // yii\web\View$optional = Yii::$app->get('exampleView', false); // yii\web\View|null$unknown = Yii::$app->get('view.alias'); // object; not a configured component IDPassing false or a non-constant boolean as $throwException makes a resolved component nullable. An object
fallback does not guarantee a successful runtime lookup: unknown component IDs can throw. Use
Yii::$container->get('view.alias') for the configured container alias.
Documentation
Section titled “Documentation”Practical guides and complete examples for Yii type inference and application analysis.
- 📚 Installation Guide
- ⚙️ Configuration Guide
- 💡 Usage Examples
- 🔄 Migration Guide and Upgrade Entry Point
- 🧪 Testing Guide
AI assistance
Section titled “AI assistance”AI agents: use the repository guides and source for the installed revision.
For a documentation deployment with
llms.txt, read that index first. When Markdown export is enabled, append
index.md to a page URL. For Yii conventions, use the yii2-framework skill
from a local framework documentation checkout.
- 🤖 yii2-phpstan-analysis skill: installation for Claude Code, Codex, and OpenCode.
If the hosted sources are unavailable, use the repository guides and locally available skills.
Our social networks
Section titled “Our social networks”Follow on X Follow on Facebook Join our Subreddit Join on Telegram
License
Section titled “License”Package
Section titled “Package”- Source code and issues: yii2-extensions/phpstan. Star the repository if the package is useful to you.
- Composer package: yii2-extensions/phpstan.
- Changelog: CHANGELOG.md.