Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
LaravelPHPJune 24, 20264 min read

PHPStan Static Analysis for Enforcing Laravel Architecture Constraints

Master PHPStan static analysis to enforce strict Laravel architecture constraints. Learn to build custom rules that catch violations before they hit production.

PHPStanLaravelStatic AnalysisArchitecturePHPBackend

Last month, I spent three days refactoring a legacy Laravel codebase where developers were constantly importing Eloquent models directly into Service classes. It was a nightmare of tight coupling that made unit testing nearly impossible. We needed a way to enforce architectural boundaries automatically, and that’s when I finally dove into writing custom rules for PHPStan.

If you're tired of reviewing pull requests just to check if someone added a User::find() call in the wrong layer, static analysis is your best friend. It’s the difference between catching a mistake at 2 PM on a Tuesday and catching it at 3 AM during an on-call rotation.

Why Standard Rules Aren't Enough

PHPStan is excellent for finding undefined methods or type mismatches, but it doesn't know your domain. It doesn't care if your OrderController is calling a Database facade directly, even if your architecture guidelines explicitly forbid it.

We initially tried using simple regex-based linting in our CI pipeline. It was brittle, slow, and failed the moment someone added a comment block or changed their indentation style. We needed something that understood the Abstract Syntax Tree (AST). That’s when we switched to building rules that hook into the PHPStan analysis engine.

Setting Up Your Custom Rule

To start, you’ll need the phpstan/phpstan package installed. Your custom rule will need to implement PHPStan\Rules\Rule.

Here is a basic example of a rule that prevents developers from calling Eloquent models inside classes located in the app/Services namespace:

PHP
namespace App\PHPStan;

use PhpParser\Node;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;

class NoEloquentInServicesRule implements Rule
{
    public function getNodeType(): string
    {
        return StaticCall::class;
    }

    public function processNode(Node $node, Scope $scope): array
    {
        #6A9955">// Check if we are inside a Service class
        if (!str_contains($scope->getFile(), 'app/Services/')) {
            return [];
        }

        #6A9955">// Check if the class being called is an Eloquent model
        $class = $node->class;
        if ($class instanceof Node\Name && str_contains($class->toString(), 'Models')) {
            return ['Eloquent models should not be called directly in services.'];
        }

        return [];
    }
}

This rule is simple, but it’s powerful. It leverages the AST to ensure type safety and architectural integrity. Once you register this in your phpstan.neon file, the analysis engine will flag any violations during your build process.

Strengthening Laravel Architecture with Custom Rules

When you move beyond simple string checks, you can start enforcing complex constraints. For instance, you might want to ensure that all DTOs are immutable or that specific interfaces are implemented.

If you’re interested in how data flows through your system, check out how we handled Laravel DTO Hydration: Building Deterministic Reflection-Based Sanitizers. When you combine DTOs with custom PHPStan rules, you essentially create a type-safe contract that the compiler—or in this case, the static analyzer—enforces for you.

Handling Trade-offs and Performance

Static analysis isn't free. As your ruleset grows, so does the time it takes to run vendor/bin/phpstan. On our main monolith, adding about 15 custom rules increased our analysis time from 12 seconds to roughly 45 seconds.

For us, that trade-off was worth it. We caught around 12 architectural violations in the first week of implementation alone. If you're working on high-throughput systems, you might also want to look into Laravel Octane Memory Management: Implementing Custom Object Pooling to keep performance predictable while maintaining these strict standards.

FAQ

Can I use these rules to enforce PSR standards? You can, but I’d recommend using php-cs-fixer for style issues. Keep your custom PHPStan rules focused on domain-specific architectural constraints.

How do I test my custom rules? PHPStan provides a PHPStan\Testing\RuleTestCase class. You create a test file, pass a snippet of code, and assert that your rule returns the expected error message. It’s exactly like writing a unit test for your architecture.

Does this slow down my local development? Only if you run it on every file save. I suggest running PHPStan as a pre-commit hook or as part of your CI pipeline, rather than trying to run it in real-time inside your IDE.

Final Thoughts

Implementing custom rules in PHPStan is the most effective way to scale a team without losing your mind. It moves the burden of "policing" the code from the senior engineers to the CI pipeline. I’m still experimenting with rules that detect circular dependencies between modules, which is a significantly harder problem to solve, but I'm confident that static analysis is the right path forward.

Don't try to write every rule at once. Start with one, get it running, and watch your codebase become significantly more predictable.

Back to Blog

Similar Posts

LaravelPHPJune 24, 20264 min read

Laravel DTO Hydration: Building Deterministic Reflection-Based Sanitizers

Laravel DTO hydration using the Reflection API ensures runtime type safety. Stop passing arrays and start building deterministic, validated data objects today.

Read more
LaravelPHP
June 24, 2026
4 min read

Laravel Eloquent Query Optimization via AST-based Static Analysis

Laravel Eloquent query optimization is difficult at runtime. Learn how to use Abstract Syntax Tree (AST) analysis to detect inefficient relationship loading.

Read more
LaravelPHPJune 24, 20264 min read

Laravel Eloquent Cache-Aside: Implementing Decorators for Consistency

Master Laravel Eloquent Cache-Aside patterns using the Decorator pattern. Ensure data consistency and slash latency with this clean, production-ready guide.

Read more