bulton-fr /
methods-header-generator
| 1 | <?php |
||||||
| 2 | |||||||
| 3 | namespace bultonFr\MethodsHeaderGenerator; |
||||||
| 4 | |||||||
| 5 | use \phpDocumentor\Reflection\DocBlockFactory; |
||||||
| 6 | use \phpDocumentor\Reflection\DocBlock\Tag; |
||||||
| 7 | |||||||
| 8 | /** |
||||||
| 9 | * Parse a class and find all methods into |
||||||
| 10 | */ |
||||||
| 11 | class ClassParser |
||||||
| 12 | { |
||||||
| 13 | /** |
||||||
| 14 | * @var string $className The name (with namespace) of the class to parse |
||||||
| 15 | */ |
||||||
| 16 | protected $className = ''; |
||||||
| 17 | |||||||
| 18 | /** |
||||||
| 19 | * @var \bultonFr\MethodsHeaderGenerator\ProjectParser|null $projectParser The |
||||||
| 20 | * instance of the ProjectParser class who instanciate this class |
||||||
| 21 | */ |
||||||
| 22 | protected $projectParser; |
||||||
| 23 | |||||||
| 24 | /** |
||||||
| 25 | * @var \ReflectionClass $reflection The reflection instance who describe |
||||||
| 26 | * the class |
||||||
| 27 | */ |
||||||
| 28 | protected $reflection; |
||||||
| 29 | |||||||
| 30 | /** |
||||||
| 31 | * @var \ReflectionClass|false $reflectionParent The reflection instance of |
||||||
| 32 | * the parent class. False if no parent class. |
||||||
| 33 | */ |
||||||
| 34 | protected $reflectionParent; |
||||||
| 35 | |||||||
| 36 | /** |
||||||
| 37 | * @var \bultonFr\MethodsHeaderGenerator\ClassParser|null $pârserParent The |
||||||
| 38 | * parser instance of the parent class |
||||||
| 39 | */ |
||||||
| 40 | protected $parserParent; |
||||||
| 41 | |||||||
| 42 | /** |
||||||
| 43 | * @var \bultonFr\MethodsHeaderGenerator\ProjectParser[] $parserInterface |
||||||
| 44 | * parsers instances for each interface implemented by the class |
||||||
| 45 | */ |
||||||
| 46 | protected $parserInterfaces = []; |
||||||
| 47 | |||||||
| 48 | /** |
||||||
| 49 | * @var \phpDocumentor\Reflection\DocBlock\Tags\Method[] $dynamicMethods |
||||||
| 50 | * All methods find into class docBlock with @method |
||||||
| 51 | */ |
||||||
| 52 | protected $dynamicMethods = []; |
||||||
| 53 | |||||||
| 54 | /** |
||||||
| 55 | * @var \bultonFr\MethodsHeaderGenerator\MethodParser[] $methods All methods |
||||||
| 56 | * find into the class who are parsed. |
||||||
| 57 | */ |
||||||
| 58 | protected $methods = []; |
||||||
| 59 | |||||||
| 60 | /** |
||||||
| 61 | * @var int $runStatus The current status of the run method. |
||||||
| 62 | * * 0 : run() has never be called |
||||||
| 63 | * * 1 : run() is currently called |
||||||
| 64 | * * 2 : run() has been called |
||||||
| 65 | * It's a security to not re-call run when we are already on it. When a |
||||||
| 66 | * class have a dependency loop (should not be existing). |
||||||
| 67 | */ |
||||||
| 68 | protected $runStatus = 0; |
||||||
| 69 | |||||||
| 70 | /** |
||||||
| 71 | * Construct |
||||||
| 72 | * Instanciate ReflectionClass for the asked class and get the |
||||||
| 73 | * ReflectionClass for parent class too. |
||||||
| 74 | * |
||||||
| 75 | * @param string $className |
||||||
| 76 | * @param \bultonFr\MethodsHeaderGenerator\ProjectParser|null $projectParser |
||||||
| 77 | * The instance of ProjectParser If the class is instanciate from him, |
||||||
| 78 | * else null. |
||||||
| 79 | * It's used to improve performance (not re-parse a class) |
||||||
| 80 | */ |
||||||
| 81 | public function __construct($className, $projectParser=null) |
||||||
| 82 | { |
||||||
| 83 | $this->className = $className; |
||||||
| 84 | $this->projectParser = $projectParser; |
||||||
| 85 | $this->reflection = new \ReflectionClass($this->className); |
||||||
| 86 | |||||||
| 87 | $this->reflectionParent = $this->reflection->getParentClass(); |
||||||
| 88 | } |
||||||
| 89 | |||||||
| 90 | /** |
||||||
| 91 | * Getter accessor to property className |
||||||
| 92 | * |
||||||
| 93 | * @return string |
||||||
| 94 | */ |
||||||
| 95 | public function getClassName() |
||||||
| 96 | { |
||||||
| 97 | return $this->className; |
||||||
| 98 | } |
||||||
| 99 | |||||||
| 100 | /** |
||||||
| 101 | * Getter accessor to property projectParser |
||||||
| 102 | * |
||||||
| 103 | * @return \bultonFr\MethodsHeaderGenerator\ProjectParser|null |
||||||
| 104 | */ |
||||||
| 105 | public function getProjectParser() |
||||||
| 106 | { |
||||||
| 107 | return $this->projectParser; |
||||||
| 108 | } |
||||||
| 109 | |||||||
| 110 | /** |
||||||
| 111 | * Getter accessor to property reflection |
||||||
| 112 | * |
||||||
| 113 | * @return \ReflectionClass |
||||||
| 114 | */ |
||||||
| 115 | public function getReflection() |
||||||
| 116 | { |
||||||
| 117 | return $this->reflection; |
||||||
| 118 | } |
||||||
| 119 | |||||||
| 120 | /** |
||||||
| 121 | * Getter accessor to property reflectionParent |
||||||
| 122 | * |
||||||
| 123 | * @return \ReflectionClass|false |
||||||
| 124 | */ |
||||||
| 125 | public function getReflectionParent() |
||||||
| 126 | { |
||||||
| 127 | return $this->reflectionParent; |
||||||
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||||||
| 128 | } |
||||||
| 129 | |||||||
| 130 | /** |
||||||
| 131 | * Getter accessor to property parserParent |
||||||
| 132 | * |
||||||
| 133 | * @return \bultonFr\MethodsHeaderGenerator\ClassParser|null |
||||||
| 134 | */ |
||||||
| 135 | public function getParserParent() |
||||||
| 136 | { |
||||||
| 137 | return $this->parserParent; |
||||||
| 138 | } |
||||||
| 139 | |||||||
| 140 | /** |
||||||
| 141 | * Getter accessor to property parserInterfaces |
||||||
| 142 | * |
||||||
| 143 | * @return \bultonFr\MethodsHeaderGenerator\ProjectParser[] |
||||||
| 144 | */ |
||||||
| 145 | public function getParserInterfaces() |
||||||
| 146 | { |
||||||
| 147 | return $this->parserInterfaces; |
||||||
| 148 | } |
||||||
| 149 | |||||||
| 150 | /** |
||||||
| 151 | * Getter accessor to property dynamicMethods |
||||||
| 152 | * |
||||||
| 153 | * @return \phpDocumentor\Reflection\DocBlock\Tags\Method[] |
||||||
| 154 | */ |
||||||
| 155 | public function getDynamicMethods() |
||||||
| 156 | { |
||||||
| 157 | return $this->dynamicMethods; |
||||||
| 158 | } |
||||||
| 159 | |||||||
| 160 | /** |
||||||
| 161 | * Getter accessor to property methods |
||||||
| 162 | * |
||||||
| 163 | * @return \bultonFr\MethodsHeaderGenerator\MethodParser[] |
||||||
| 164 | */ |
||||||
| 165 | public function getMethods() |
||||||
| 166 | { |
||||||
| 167 | return $this->methods; |
||||||
| 168 | } |
||||||
| 169 | |||||||
| 170 | /** |
||||||
| 171 | * Getter accessor to property runStatus |
||||||
| 172 | * |
||||||
| 173 | * @return int |
||||||
| 174 | */ |
||||||
| 175 | public function getRunStatus() |
||||||
| 176 | { |
||||||
| 177 | return $this->runStatus; |
||||||
| 178 | } |
||||||
| 179 | |||||||
| 180 | /** |
||||||
| 181 | * Run the parser to analyse class methods |
||||||
| 182 | * |
||||||
| 183 | * @throws \Exception |
||||||
| 184 | * |
||||||
| 185 | * @return void |
||||||
| 186 | */ |
||||||
| 187 | public function run() |
||||||
| 188 | { |
||||||
| 189 | if ($this->runStatus === 1) { |
||||||
| 190 | throw new \Exception( |
||||||
| 191 | 'You are already on the run method.' |
||||||
| 192 | .' Maybe you have an dependency loop.' |
||||||
| 193 | ); |
||||||
| 194 | } |
||||||
| 195 | |||||||
| 196 | $this->runStatus = 1; |
||||||
| 197 | |||||||
| 198 | $this->instantiateParentParser(); |
||||||
| 199 | $this->instantiateInterfacesParser(); |
||||||
| 200 | |||||||
| 201 | $this->analyseDocBlock(); |
||||||
| 202 | $this->analyseMethods(); |
||||||
| 203 | |||||||
| 204 | $this->runStatus = 2; |
||||||
| 205 | } |
||||||
| 206 | |||||||
| 207 | /** |
||||||
| 208 | * Instantiate de parser for the parent class |
||||||
| 209 | * |
||||||
| 210 | * @return void |
||||||
| 211 | */ |
||||||
| 212 | protected function instantiateParentParser() |
||||||
| 213 | { |
||||||
| 214 | if ($this->reflectionParent === false) { |
||||||
| 215 | return; |
||||||
| 216 | } |
||||||
| 217 | |||||||
| 218 | $this->parserParent = $this->newParser($this->reflectionParent->name); |
||||||
| 219 | $this->parserParent->run(); |
||||||
| 220 | } |
||||||
| 221 | |||||||
| 222 | /** |
||||||
| 223 | * Instantiate the parser for all interfaces |
||||||
| 224 | * |
||||||
| 225 | * @return void |
||||||
| 226 | */ |
||||||
| 227 | protected function instantiateInterfacesParser() |
||||||
| 228 | { |
||||||
| 229 | foreach ($this->reflection->getInterfaces() as $interface) { |
||||||
| 230 | $interfaceParser = $this->newParser($interface->name); |
||||||
| 231 | $interfaceParser->run(); |
||||||
| 232 | |||||||
| 233 | $this->parserInterfaces[] = $interfaceParser; |
||||||
| 234 | } |
||||||
| 235 | } |
||||||
| 236 | |||||||
| 237 | /** |
||||||
| 238 | * Analyse all tags into the class docBlock. |
||||||
| 239 | * |
||||||
| 240 | * @return void |
||||||
| 241 | */ |
||||||
| 242 | protected function analyseDocBlock() |
||||||
| 243 | { |
||||||
| 244 | $classDocBlock = $this->reflection->getDocComment(); |
||||||
| 245 | if ($classDocBlock === false) { |
||||||
| 246 | return; |
||||||
| 247 | } |
||||||
| 248 | |||||||
| 249 | $docBlockFactory = DocBlockFactory::createInstance(); |
||||||
| 250 | $docBlock = $docBlockFactory->create($classDocBlock); |
||||||
|
0 ignored issues
–
show
It seems like
$classDocBlock can also be of type true; however, parameter $docblock of phpDocumentor\Reflection\DocBlockFactory::create() does only seem to accept object|string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 251 | $tagsList = $docBlock->getTags(); |
||||||
| 252 | |||||||
| 253 | foreach ($tagsList as $tagInfos) { |
||||||
| 254 | $this->analyseDocBlockTag($tagInfos); |
||||||
| 255 | } |
||||||
| 256 | } |
||||||
| 257 | |||||||
| 258 | /** |
||||||
| 259 | * Analyse all methods find into the class by the reflection class |
||||||
| 260 | * |
||||||
| 261 | * @return void |
||||||
| 262 | */ |
||||||
| 263 | protected function analyseMethods() |
||||||
| 264 | { |
||||||
| 265 | $methods = $this->reflection->getMethods(); |
||||||
| 266 | |||||||
| 267 | foreach ($methods as $method) { |
||||||
| 268 | $methodParser = new MethodParser($this, $method); |
||||||
| 269 | $methodParser->run(); |
||||||
| 270 | |||||||
| 271 | $this->methods[$method->name] = $methodParser; |
||||||
| 272 | } |
||||||
| 273 | } |
||||||
| 274 | |||||||
| 275 | /** |
||||||
| 276 | * Instantiate a new ClassParser object. |
||||||
| 277 | * Usefull if we use ProjectParser. In this case, we check ProjectParser |
||||||
| 278 | * before to know if the class to parse has not been already parsed. If the |
||||||
| 279 | * class was already parsed, we use it and not re-parse it again. |
||||||
| 280 | * |
||||||
| 281 | * @param string $className The class name to parse |
||||||
| 282 | * |
||||||
| 283 | * @return \bultonFr\MethodsHeaderGenerator\ClassParser |
||||||
| 284 | */ |
||||||
| 285 | protected function newParser($className) |
||||||
| 286 | { |
||||||
| 287 | if ($this->projectParser === null) { |
||||||
| 288 | return new ClassParser($className); |
||||||
| 289 | } |
||||||
| 290 | |||||||
| 291 | if ($this->projectParser->hasClasses($className)) { |
||||||
| 292 | return $this->projectParser->getClassesByName($className); |
||||||
| 293 | } |
||||||
| 294 | |||||||
| 295 | $parser = new ClassParser($className); |
||||||
| 296 | $this->projectParser->addToClasses($parser); |
||||||
| 297 | return $parser; |
||||||
| 298 | } |
||||||
| 299 | |||||||
| 300 | /** |
||||||
| 301 | * Analyse all tag find into the class docBlock |
||||||
| 302 | * |
||||||
| 303 | * @param \phpDocumentor\Reflection\DocBlock\Tag $tagInfos The tag instance |
||||||
| 304 | * |
||||||
| 305 | * @return void |
||||||
| 306 | */ |
||||||
| 307 | protected function analyseDocBlockTag(Tag $tagInfos) |
||||||
| 308 | { |
||||||
| 309 | if ($tagInfos->getName() === 'method') { |
||||||
| 310 | $this->parseTagMethod($tagInfos); |
||||||
| 311 | } |
||||||
| 312 | } |
||||||
| 313 | |||||||
| 314 | /** |
||||||
| 315 | * Parse the tag @method and get datas from it |
||||||
| 316 | * |
||||||
| 317 | * @param \phpDocumentor\Reflection\DocBlock\Tag $tagInfos The tag instance |
||||||
| 318 | * |
||||||
| 319 | * @return void |
||||||
| 320 | */ |
||||||
| 321 | protected function parseTagMethod(Tag $tagInfos) |
||||||
| 322 | { |
||||||
| 323 | $methodName = $tagInfos->getMethodName(); |
||||||
|
0 ignored issues
–
show
The method
getMethodName() does not exist on phpDocumentor\Reflection\DocBlock\Tag. It seems like you code against a sub-type of phpDocumentor\Reflection\DocBlock\Tag such as phpDocumentor\Reflection\DocBlock\Tags\Method.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 324 | |||||||
| 325 | $this->dynamicMethods[$methodName] = $tagInfos->__toString(); |
||||||
| 326 | } |
||||||
| 327 | |||||||
| 328 | /** |
||||||
| 329 | * PHP Magic method __toString |
||||||
| 330 | * Called when a class is treated like a string. |
||||||
| 331 | * |
||||||
| 332 | * Display class name, parent class name and interfaces names. After show |
||||||
| 333 | * all methods find into docblock with tag @method, and show all methods |
||||||
| 334 | * declared into the class. |
||||||
| 335 | * |
||||||
| 336 | * @link http://php.net/manual/en/language.oop5.magic.php#object.tostring |
||||||
| 337 | * |
||||||
| 338 | * @return string |
||||||
| 339 | */ |
||||||
| 340 | public function __toString() |
||||||
| 341 | { |
||||||
| 342 | $str = $this->obtainClassNameInfos()."\n"; |
||||||
| 343 | |||||||
| 344 | //Sort methods by name |
||||||
| 345 | ksort($this->dynamicMethods); |
||||||
| 346 | ksort($this->methods); |
||||||
| 347 | |||||||
| 348 | foreach ($this->dynamicMethods as $methodStr) { |
||||||
| 349 | $str .= $methodStr."\n"; |
||||||
| 350 | } |
||||||
| 351 | |||||||
| 352 | foreach ($this->methods as $method) { |
||||||
| 353 | //Not display parent class methods who are not be override |
||||||
| 354 | if ($method->getReflection()->class !== $this->reflection->name) { |
||||||
| 355 | continue; |
||||||
| 356 | } |
||||||
| 357 | |||||||
| 358 | $str .= $method."\n"; |
||||||
| 359 | } |
||||||
| 360 | |||||||
| 361 | return $str; |
||||||
| 362 | } |
||||||
| 363 | |||||||
| 364 | /** |
||||||
| 365 | * Obtain class name with parent class name and interfaces names |
||||||
| 366 | * |
||||||
| 367 | * @return string |
||||||
| 368 | */ |
||||||
| 369 | public function obtainClassNameInfos() |
||||||
| 370 | { |
||||||
| 371 | $str = $this->className; |
||||||
| 372 | |||||||
| 373 | if ($this->reflectionParent !== false) { |
||||||
| 374 | $str .= ' extends '.$this->reflectionParent->name; |
||||||
| 375 | } |
||||||
| 376 | |||||||
| 377 | $interfaces = $this->reflection->getInterfaces(); |
||||||
| 378 | if (!empty($interfaces)) { |
||||||
| 379 | $str .= ' implements '; |
||||||
| 380 | |||||||
| 381 | foreach ($interfaces as $interfaceIndex => $interfaceInfos) { |
||||||
| 382 | if ($interfaceIndex > 0) { |
||||||
| 383 | $str .= ', '; |
||||||
| 384 | } |
||||||
| 385 | |||||||
| 386 | $str .= $interfaceInfos->name; |
||||||
| 387 | } |
||||||
| 388 | } |
||||||
| 389 | |||||||
| 390 | return $str; |
||||||
| 391 | } |
||||||
| 392 | } |
||||||
| 393 |