ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
LegacyClassUsageRule.php
Go to the documentation of this file.
1 <?php
2 
20 
24 use PhpParser\Node;
27 
28 abstract class LegacyClassUsageRule implements Rule
29 {
30  protected ReflectionProvider $reflectionProvider;
31  protected \PHPStan\Rules\Generics\GenericAncestorsCheck $genericAncestorsCheck;
32  private array $forbidden_classes = [];
33  private array $ancestor_cache = [];
34 
35  public function __construct(
36  ReflectionProvider $reflectionProvider,
37  \PHPStan\Rules\Generics\GenericAncestorsCheck $genericAncestorsCheck
38  ) {
39  $this->reflectionProvider = $reflectionProvider;
40  $this->genericAncestorsCheck = $genericAncestorsCheck;
41 
42  // Determine possible class-names (parents and children) of the forbidden classes
43  $forbidden_classes = [];
44 
45  foreach ($this->getForbiddenClasses() as $forbidden_class) {
46  $ancestors = $this->getClassAncestors($forbidden_class);
47  $this->cacheAncestors($forbidden_class, $ancestors);
48  $forbidden_classes = array_merge(
49  $forbidden_classes,
50  $ancestors
51  );
52  }
53 
54  $this->forbidden_classes = array_unique($forbidden_classes);
55  }
56 
57  private function getClassAncestors(string $class_name): array
58  {
59  if (isset($this->ancestor_cache[$class_name])) {
60  return $this->ancestor_cache[$class_name];
61  }
62 
63  $ancestors[] = $class_name;
64 
65  try {
66  $reflection = $this->reflectionProvider->getClass($class_name);
67  $ancestors = array_merge($ancestors, $reflection->getParentClassesNames());
68  } catch (\PHPStan\Broker\ClassNotFoundException $e) {
69  // Do nothing
70  } finally {
71  unset($reflection);
72  }
73  return array_unique($ancestors);
74  }
75 
76  private function cacheAncestors($class_name, array $ancestor_classes): void
77  {
78  $this->ancestor_cache[$class_name] = $ancestor_classes;
79  }
80 
81  public function getNodeType(): string
82  {
83  return CallLike::class;
84  }
85 
86  abstract protected function getForbiddenClasses(): array;
87 
88  abstract protected function getHumanReadableRuleName(): string;
89 
90  abstract protected function getRelevantILIASVersion(): int;
91 
92  final public function processNode(Node $node, Scope $scope): array
93  {
94  switch (true) {
95  case $node instanceof Node\Expr\StaticCall:
96  case $node instanceof Node\Expr\New_:
97  if ($node->class instanceof Node\Name) {
98  $class_name = $node->class->toString();
99  } else {
100  return [];
101  }
102  break;
103  default:
104  return [];
105  }
106 
107  $class_names_to_test = $this->getClassAncestors($class_name);
108 
109  $array_intersect = array_intersect($class_names_to_test, $this->forbidden_classes);
110  if ($array_intersect !== []) {
111  $this->cacheAncestors($class_name, $class_names_to_test);
112  return [
113  RuleErrorBuilder::message("Usage of $class_name is forbidden.")
114  ->metadata([
115  'rule' => $this->getHumanReadableRuleName(),
116  'version' => $this->getRelevantILIASVersion(),
117  ])
118  ->build()
119  ];
120  }
121 
122  return [];
123  }
124 }
cacheAncestors($class_name, array $ancestor_classes)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
PHPStan Rules Generics GenericAncestorsCheck $genericAncestorsCheck
__construct(ReflectionProvider $reflectionProvider, \PHPStan\Rules\Generics\GenericAncestorsCheck $genericAncestorsCheck)