Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save TomasVotruba/67f89ebfc073505dc877427221eefb45 to your computer and use it in GitHub Desktop.
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
<?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