Created
June 25, 2025 17:29
-
-
Save TomasVotruba/67f89ebfc073505dc877427221eefb45 to your computer and use it in GitHub Desktop.
[phpstan] rule - use constructor over the same old same setters again and again
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Utils\PHPStan\Rule; | |
use PhpParser\Node; | |
use PHPStan\Analyser\Scope; | |
use PHPStan\Node\CollectedDataNode; | |
use PHPStan\Rules\Rule; | |
use PHPStan\Rules\RuleError; | |
use PHPStan\Rules\RuleErrorBuilder; | |
use Utils\PHPStan\Collector\NewWithFollowingSettersCollector; | |
/** | |
* @see NewWithFollowingSettersCollector | |
* @implements Rule<CollectedDataNode> | |
*/ | |
final class AvoidAlwaysCalledSettersOnNewObjectRule implements Rule | |
{ | |
/** | |
* @var string | |
*/ | |
private const ERROR_MESSAGE = 'Class "%s" is always created with same %d setters.%sConsider passing these values via constructor instead.'; | |
public function getNodeType(): string | |
{ | |
return CollectedDataNode::class; | |
} | |
/** | |
* @param CollectedDataNode $node | |
* @return RuleError[] | |
*/ | |
public function processNode(Node $node, Scope $scope): array | |
{ | |
$collectedDataByFile = $node->get(NewWithFollowingSettersCollector::class); | |
// group class + always called setters | |
// if 0 setters, skipp it | |
// if its always the same setters, report it | |
$classesToSetters = []; | |
foreach ($collectedDataByFile as $collectedData) { | |
foreach ($collectedData as $collectedItem) { | |
if (count($collectedItem[NewWithFollowingSettersCollector::SETTER_NAMES]) === 0) { | |
continue; | |
} | |
$className = $collectedItem['className']; | |
$uniqueSetterNames = array_unique($collectedItem[NewWithFollowingSettersCollector::SETTER_NAMES]); | |
$settersCount = count($uniqueSetterNames); | |
$classesToSetters[$className][] = $settersCount; | |
} | |
} | |
$ruleErrors = []; | |
foreach ($classesToSetters as $className => $uniqueSetterCounts) { | |
// if all counters are the same, report it | |
if (count(array_unique($uniqueSetterCounts)) !== 1) { | |
continue; | |
} | |
$uniqueSetterCount = (int) $uniqueSetterCounts[0]; | |
$ruleErrors[] = RuleErrorBuilder::message(sprintf(self::ERROR_MESSAGE, $className, $uniqueSetterCount, PHP_EOL)) | |
->identifier('utils.phpstan.avoidAlwaysCalledSettersOnNewObject') | |
// @todo use reflection to the class location + line number | |
->build(); | |
} | |
return $ruleErrors; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment