This package is abandoned and no longer maintained. The author suggests using the symplify/phpstan-rules package instead.

Prefer constructor over always called setters

Maintainers

Package info

github.com/TomasVotruba/ctor

Type:phpstan-extension

pkg:composer/tomasvotruba/ctor

Statistics

Installs: 25 258

Dependents: 14

Suggesters: 0

Stars: 16

Open Issues: 0

2.2.5 2026-05-29 16:15 UTC

This package is auto-updated.

Last update: 2026-06-07 19:03:37 UTC


README

Downloads

⚠️ This package is deprecated. The rule has been merged into symplify/phpstan-rules, use it instead:

composer require symplify/phpstan-rules --dev

Then enable the rule in your phpstan.neon:

parameters:
    ctor: true


If you can use constructor instead of setters, use it. These PHPStan rules will help you to find such cases.


What It Does

This tool collects instances of new object() followed by a series of method calls on the same object:

$human = new Human();
$human->setName('Tomas');
$human->setAge(35);

...and suggests turning them into constructor arguments:

$human = new Human('Tomas', 35);

// named arguments work too, if the constructor grows wide
$human = new Human(name: 'Tomas', age: 35);

Both set* and add* method prefixes are treated as setters, so $collection->addItem(...) chains are flagged the same way.

Why?

Such chained setters often indicate implicit required dependencies. By moving them to the constructor, you make the object state explicit, safer, and easier to reason about — and even easier to test.


Requirements

  • PHP 7.2+
  • PHPStan ^2.1

Installation

composer require tomasvotruba/ctor --dev

Usage

Use phpstan/extension-installer to load the extension automatically. Run PHPStan and the rule will pick up.

Without the extension installer, include the config manually in your phpstan.neon:

includes:
    - vendor/tomasvotruba/ctor/config/extension.neon

What You'll See

When the rule fires, PHPStan reports:

Class "App\Human" is always created with same 2 setter(s): "setAge()", "setName()"
Pass these values via constructor instead

The error identifier is tv.newOverSetters — use it to ignore specific cases via PHPStan's ignoreErrors.


When the Rule Fires (and When It Doesn't)

The rule is intentionally conservative. It only reports a class when:

  • The same class is instantiated at least twice across the analysed code, with the same set of setters each time. A single new + setters block on its own is not enough — there must be a repeated pattern.

It deliberately skips:

  • Doctrine entities (files containing @ORM\Entity or #[Entity])
  • Symfony HttpKernel\Kernel subclasses
  • Vendor code
  • new + setters blocks interrupted by a return or throw (likely conditional construction)

Happy coding!