Skip to content

Instantly share code, notes, and snippets.

@xphere
Created June 16, 2019 19:40
Show Gist options
  • Save xphere/0a8331a100bc5e0dc2a66d670c772bc8 to your computer and use it in GitHub Desktop.
Save xphere/0a8331a100bc5e0dc2a66d670c772bc8 to your computer and use it in GitHub Desktop.
A PhpStan rule to ban changes on public members outside a class.
<?php declare(strict_types=1);
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\AssignOp;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Identifier;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Properties\PropertyReflectionFinder;
use PHPStan\Rules\Rule;
use function iterator_to_array;
final class DontWriteToPublicPropertiesRule implements Rule
{
public function __construct(PropertyReflectionFinder $propertyReflector)
{
$this->propertyReflector = $propertyReflector;
}
public function getNodeType(): string
{
return Expr::class;
}
public function processNode(Node $node, Scope $scope): array
{
return iterator_to_array($this->validate($node, $scope), false);
}
private function validate(Node $node, Scope $scope)
{
if (!$node instanceof Assign && !$node instanceof AssignOp) {
return;
}
$property = $node->var;
if (!$property instanceof PropertyFetch && !$property instanceof StaticPropertyFetch) {
return;
}
if (!$property->name instanceof Identifier) {
return;
}
$reflection = $this
->propertyReflector
->findPropertyReflectionFromNode(
$property,
$scope
)
;
if ($reflection === null) {
return;
}
if ($scope->getClassReflection() === $reflection->getDeclaringClass()) {
return;
}
yield sprintf(
'Cannot write to public property "%s:%s".',
$reflection->getDeclaringClass()->getName(),
$property->name
);
}
private $propertyReflector;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment