Complex classes like ClassProxy often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ClassProxy, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 37 | class ClassProxy extends AbstractProxy |
||
| 38 | { |
||
| 39 | /** |
||
| 40 | * Parent class reflection |
||
| 41 | * |
||
| 42 | * @var null|ParsedClass |
||
| 43 | */ |
||
| 44 | protected $class = null; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Parent class name, can be changed manually |
||
| 48 | * |
||
| 49 | * @var string |
||
| 50 | */ |
||
| 51 | protected $parentClassName = null; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * Source code for methods |
||
| 55 | * |
||
| 56 | * @var array Name of method => source code for it |
||
| 57 | */ |
||
| 58 | protected $methodsCode = []; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Static mappings for class name for excluding if..else check |
||
| 62 | * |
||
| 63 | * @var null|array |
||
| 64 | */ |
||
| 65 | protected static $invocationClassMap = [ |
||
| 66 | AspectContainer::METHOD_PREFIX => DynamicClosureSplatMethodInvocation::class, |
||
| 67 | AspectContainer::STATIC_METHOD_PREFIX => StaticClosureMethodInvocation::class, |
||
| 68 | AspectContainer::PROPERTY_PREFIX => ClassFieldAccess::class, |
||
| 69 | AspectContainer::STATIC_INIT_PREFIX => StaticInitializationJoinpoint::class, |
||
| 70 | AspectContainer::INIT_PREFIX => ReflectionConstructorInvocation::class |
||
| 71 | ]; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * List of additional interfaces to implement |
||
| 75 | * |
||
| 76 | * @var array |
||
| 77 | */ |
||
| 78 | protected $interfaces = []; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * List of additional traits for using |
||
| 82 | * |
||
| 83 | * @var array |
||
| 84 | */ |
||
| 85 | protected $traits = []; |
||
| 86 | |||
| 87 | /** |
||
| 88 | * Source code for properties |
||
| 89 | * |
||
| 90 | * @var array Name of property => source code for it |
||
| 91 | */ |
||
| 92 | protected $propertiesCode = []; |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Name for the current class |
||
| 96 | * |
||
| 97 | * @var string |
||
| 98 | */ |
||
| 99 | protected $name = ''; |
||
| 100 | |||
| 101 | /** |
||
| 102 | * Flag to determine if we need to add a code for property interceptors |
||
| 103 | * |
||
| 104 | * @var bool |
||
| 105 | */ |
||
| 106 | private $isFieldsIntercepted = false; |
||
| 107 | |||
| 108 | /** |
||
| 109 | * List of intercepted properties names |
||
| 110 | * |
||
| 111 | * @var array |
||
| 112 | */ |
||
| 113 | private $interceptedProperties = []; |
||
| 114 | |||
| 115 | /** |
||
| 116 | * Generates an child code by parent class reflection and joinpoints for it |
||
| 117 | * |
||
| 118 | * @param ParsedClass $parent Parent class reflection |
||
| 119 | * @param array|Advice[] $classAdvices List of advices for class |
||
| 120 | * |
||
| 121 | * @throws \InvalidArgumentException if there are unknown type of advices |
||
| 122 | */ |
||
| 123 | 5 | public function __construct(ParsedClass $parent, array $classAdvices) |
|
| 179 | |||
| 180 | |||
| 181 | /** |
||
| 182 | * Updates parent name for child |
||
| 183 | * |
||
| 184 | * @param string $newParentName New class name |
||
| 185 | * |
||
| 186 | * @return static |
||
| 187 | */ |
||
| 188 | 5 | public function setParentName($newParentName) |
|
| 194 | |||
| 195 | /** |
||
| 196 | * Override parent method with new body |
||
| 197 | * |
||
| 198 | * @param string $methodName Method name to override |
||
| 199 | * @param string $body New body for method |
||
| 200 | * |
||
| 201 | * @return static |
||
| 202 | */ |
||
| 203 | 5 | public function override($methodName, $body) |
|
| 209 | |||
| 210 | /** |
||
| 211 | * Creates a method |
||
| 212 | * |
||
| 213 | * @param int $methodFlags See ReflectionMethod modifiers |
||
| 214 | * @param string $methodName Name of the method |
||
| 215 | * @param bool $byReference Is method should return value by reference |
||
| 216 | * @param string $body Body of method |
||
| 217 | * @param string $parameters Definition of parameters |
||
| 218 | * |
||
| 219 | * @return static |
||
| 220 | */ |
||
| 221 | public function setMethod($methodFlags, $methodName, $byReference, $body, $parameters) |
||
| 239 | |||
| 240 | /** |
||
| 241 | * Inject advices into given class |
||
| 242 | * |
||
| 243 | * NB This method will be used as a callback during source code evaluation to inject joinpoints |
||
| 244 | * |
||
| 245 | * @param string $className Aop child proxy class |
||
| 246 | * @param array|Advice[] $advices List of advices to inject into class |
||
| 247 | * |
||
| 248 | * @return void |
||
| 249 | */ |
||
| 250 | public static function injectJoinPoints($className, array $advices = []) |
||
| 264 | |||
| 265 | /** |
||
| 266 | * Wrap advices with joinpoint object |
||
| 267 | * |
||
| 268 | * @param array|Advice[] $classAdvices Advices for specific class |
||
| 269 | * @param string $className Name of the original class to use |
||
| 270 | * |
||
| 271 | * @throws \UnexpectedValueException If joinPoint type is unknown |
||
| 272 | * |
||
| 273 | * NB: Extension should be responsible for wrapping advice with join point. |
||
| 274 | * |
||
| 275 | * @return array|Joinpoint[] returns list of joinpoint ready to use |
||
| 276 | */ |
||
| 277 | protected static function wrapWithJoinPoints($classAdvices, $className) |
||
| 307 | |||
| 308 | /** |
||
| 309 | * Add an interface for child |
||
| 310 | * |
||
| 311 | * @param string|ReflectionClass|ParsedClass $interface |
||
| 312 | * |
||
| 313 | * @throws \InvalidArgumentException If object is not an interface |
||
| 314 | */ |
||
| 315 | 5 | public function addInterface($interface) |
|
| 327 | |||
| 328 | /** |
||
| 329 | * Add a trait for child |
||
| 330 | * |
||
| 331 | * @param string|ReflectionClass|ParsedClass $trait |
||
| 332 | * |
||
| 333 | * @throws \InvalidArgumentException If object is not a trait |
||
| 334 | */ |
||
| 335 | public function addTrait($trait) |
||
| 347 | |||
| 348 | /** |
||
| 349 | * Creates a property |
||
| 350 | * |
||
| 351 | * @param int $propFlags See ReflectionProperty modifiers |
||
| 352 | * @param string $propName Name of the property |
||
| 353 | * @param null|string $defaultText Default value, should be string text! |
||
| 354 | * |
||
| 355 | * @return static |
||
| 356 | */ |
||
| 357 | 5 | public function setProperty($propFlags, $propName, $defaultText = null) |
|
| 370 | |||
| 371 | /** |
||
| 372 | * Adds a definition for joinpoints private property in the class |
||
| 373 | * |
||
| 374 | * @return void |
||
| 375 | */ |
||
| 376 | 5 | protected function addJoinpointsProperty() |
|
| 384 | |||
| 385 | /** |
||
| 386 | * Override parent method with joinpoint invocation |
||
| 387 | * |
||
| 388 | * @param ParsedMethod $method Method reflection |
||
| 389 | */ |
||
| 390 | 5 | protected function overrideMethod(ParsedMethod $method) |
|
| 397 | |||
| 398 | /** |
||
| 399 | * Creates definition for method body |
||
| 400 | * |
||
| 401 | * @param ParsedMethod $method Method reflection |
||
| 402 | * |
||
| 403 | * @return string new method body |
||
| 404 | */ |
||
| 405 | 5 | protected function getJoinpointInvocationBody(ParsedMethod $method) |
|
| 422 | |||
| 423 | /** |
||
| 424 | * Makes property intercepted |
||
| 425 | * |
||
| 426 | * @param ParsedProperty $property Reflection of property to intercept |
||
| 427 | */ |
||
| 428 | protected function interceptProperty(ParsedProperty $property) |
||
| 433 | |||
| 434 | /** |
||
| 435 | * {@inheritDoc} |
||
| 436 | */ |
||
| 437 | 5 | public function __toString() |
|
| 468 | |||
| 469 | /** |
||
| 470 | * Add code for intercepting properties |
||
| 471 | * |
||
| 472 | * @param null|ParsedMethod $constructor Constructor reflection or null |
||
| 473 | */ |
||
| 474 | protected function addFieldInterceptorsCode(ParsedMethod $constructor = null) |
||
| 487 | |||
| 488 | /** |
||
| 489 | * Creates a method code from Reflection |
||
| 490 | * |
||
| 491 | * @param ParsedMethod $method Reflection for method |
||
| 492 | * @param string $body Body of method |
||
| 493 | * |
||
| 494 | * @return string |
||
| 495 | */ |
||
| 496 | 5 | protected function getOverriddenMethod(ParsedMethod $method, $body) |
|
| 514 | |||
| 515 | /** |
||
| 516 | * Returns a code for magic getter to perform interception |
||
| 517 | * |
||
| 518 | * @return string |
||
| 519 | */ |
||
| 520 | private function getMagicGetterBody() |
||
| 538 | |||
| 539 | /** |
||
| 540 | * Returns a code for magic setter to perform interception |
||
| 541 | * |
||
| 542 | * @return string |
||
| 543 | */ |
||
| 544 | private function getMagicSetterBody() |
||
| 561 | |||
| 562 | /** |
||
| 563 | * Returns constructor code |
||
| 564 | * |
||
| 565 | * @param ParsedMethod $constructor Constructor reflection |
||
| 566 | * @param bool $isCallParent Is there is a need to call parent code |
||
| 567 | * |
||
| 568 | * @return string |
||
| 569 | */ |
||
| 570 | private function getConstructorBody(ParsedMethod $constructor = null, $isCallParent = false) |
||
| 598 | } |
||
| 599 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.jsonfile (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.jsonto be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
requireorrequire-devsection?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceofchecks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.