Search by

gboquizosanchez / phpstan-code-limits

gboquizosanchez

PHPStan rules that enforce size, layout and expression limits on PHP code

Package info

github.com/gboquizosanchez/phpstan-code-limits

Type:phpstan-extension

pkg:composer/gboquizosanchez/phpstan-code-limits

Statistics

Installs: 11

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2.0 2026-10-21 10:49 UTC

This package is auto-updated.

Last update: 2026-10-21 11:23:34 UTC


README

Code Limits

gboquizosanchez/phpstan-code-limits

Size, layout and expression limits for PHP code, as PHPStan rules

Latest Stable Version Total Downloads PHP License: MIT PHPStan Tests

Too many parameters, a 120-character signature, a non-static closure? composer test fails until it is fixed.

Why code limits?

Style rules written in a guide get skipped, and reviewing them by hand is slow. This extension turns each limit into a regular PHPStan error with its own identifier, so the gate fails and whoever wrote the code fixes it before review.

Problem Without code limits With code limits
A method grows to 6 parameters ❌ Spotted in review, maybe ✅ codeLimits.params fails the analysis
A long signature on a single line ❌ Reformatted by hand ✅ codeLimits.signature points at it
A closure that could be static ❌ Nobody notices ✅ codeLimits.closureStatic
A function nobody can follow anymore ❌ Grows until it breaks ✅ Cognitive complexity capped at 15
One rule does not fit a folder ❌ Ad hoc exceptions ✅ PHPStan's own ignoreErrors

Version compatibility

Package PHPStan PHP
1.x 2.x ^8.4

🚀 Features

  • One identifier per limit: every error is codeLimits.<rule>, so each limit can be ignored on its own.
  • Configurable numbers: parameters, returns, methods and line length are PHPStan parameters.
  • Cognitive complexity included: ships tomasvotruba/cognitive-complexity with a function limit of 15.
  • One line of setup: code-limits-install writes a single include into your phpstan.neon, with or without phpstan/extension-installer.
  • Laravel preset: skips config/ and the skeleton's path concatenations out of the box.
  • Dev only: --dev dependency, nothing runs in production.

📦 Installation

composer require --dev gboquizosanchez/phpstan-code-limits

Then add the configuration to your phpstan.neon:

vendor/bin/code-limits-install

It writes the one line your phpstan.neon needs from this package, chosen for your project:

Project Included file
With phpstan/extension-installer complexity.neon
With phpstan/extension-installer, Laravel laravel.neon
Without phpstan/extension-installer standalone.neon
Without phpstan/extension-installer, Laravel standalone-laravel.neon

A project is Laravel when it has an artisan file. Lines written by older versions are replaced, and running it again changes nothing.

The cognitive complexity limit has to come from that line: tomasvotruba/cognitive-complexity loads its own defaults (function 9, class 40) after this extension, and with phpstan/extension-installer the extensions are already loaded, so including them again would fail.

Laravel preset

The Laravel entry points also skip the files the framework writes for you:

  • config/*: every limit, since Laravel and vendor:publish write these files.
  • bootstrap/app.php and public/index.php: codeLimits.concat, for the skeleton's __DIR__.'/../...' paths.

Those paths are resolved from the current working directory, so run PHPStan from the project root, as composer test and IDEs do.

📋 Limits

Identifier Limit
codeLimits.params At most 3 parameters per function or method. Promoted constructor parameters of a readonly class do not count.
codeLimits.returns At most 3 return statements per function or method.
codeLimits.methods At most 20 methods per class-like.
codeLimits.signature A signature longer than 80 characters has one parameter per line with a trailing comma; a shorter one stays on one line.
codeLimits.promotedCtor A constructor with promoted properties has one parameter per line with a trailing comma.
codeLimits.throw throw_if() / throw_unless() on one line when it fits in 80 characters, otherwise one argument per line; condition and message stay inline.
codeLimits.matchArm A match arm with several conditions has one condition per line with a trailing comma.
codeLimits.tuple No returning an array just to destructure it with [$a, $b] = ....
codeLimits.foreach foreach iterates over a variable, a property or a single call, and its header fits in 80 characters.
codeLimits.nestedArgs No two or more nested call levels in arguments, unless the statement fits in 80 characters.
codeLimits.closureStatic Closures and arrow functions are static unless they use $this or are bound by the framework.
codeLimits.closureUseOrder use (...) variables are ordered by first usage in the body.
codeLimits.concat String interpolation or sprintf() instead of . concatenation.
codeLimits.ellipsis Three ASCII dots ... instead of the single ellipsis character (U+2026).
complexity.functionLike Cognitive complexity of a function or method at most 15.

⚙️ Configuration

The numbers are configurable:

parameters:
    codeLimits:
        maxParameters: 3
        maxReturns: 3
        maxMethods: 20
        maxLineLength: 80
    cognitive_complexity:
        function: 15 # after the code-limits include

Turn a limit off, everywhere or for some paths, with PHPStan's own ignoreErrors:

parameters:
    ignoreErrors:
        -
            identifier: codeLimits.concat
            paths:
                - config/*

🧪 Testing

composer test

Contributing

Contributions are welcome!

  • 🐛 Report bugs via GitHub Issues
  • 💡 Suggest features or improvements
  • 🔧 Submit pull requests with fixes or enhancements

Credits

📄 License

This package is open-source software licensed under the MIT License.