A service container returning mixed and a model with magic properties defeat static analysis entirely without a framework-aware extension.
$ composer require --dev nunomaduro/larastan
# what it teaches the analyser:
# app(Foo::class) returns Foo, not mixed
# $model->column, from the migration or a docblock
# Model::where() returns a Builder, and ->first() may
# return null
# the facade signatures
# without it, level 5 is already unreachable.
The extension is not optional on a framework-heavy codebase — it is the difference between an analyser that works and one that reports thousands of false positives about magic. Model properties are the remaining gap: they come from the database and the analyser cannot see the schema, so a generated docblock per model is the usual answer and it goes stale. Generating those docblocks in CI and failing on a diff is what keeps them true.