Join points are points in the execution of the system, such as method calls,
where behavior supplied by aspects is combined. A join point is a point in
the execution of the program, which is used to define the dynamic structure
of a crosscutting concern.
/** * @dataProvider sortingTestSource */ public function testSortingLogic($advices, array $order = []) { $advices = AbstractJoinpoint::sortAdvices($advices); foreach ($advices as $advice) { $expected = array_shift($order); $this->assertInstanceOf($expected, $advice); } }
/** * Constructor for field access * * @param string $className Class name * @param string $fieldName Field name * @param $advices array List of advices for this invocation */ public function __construct($className, $fieldName, array $advices) { parent::__construct($advices); $this->reflectionProperty = $reflectionProperty = new ReflectionProperty($className, $fieldName); // Give an access to protected field if ($reflectionProperty->isProtected()) { $reflectionProperty->setAccessible(true); } }
/** * Constructor for static initialization joinpoint * * @param string $className Name of the class * @param string $type Type of joinpoint * @param $advices array List of advices for this invocation * * @internal param ReflectionClass $reflectionClass Reflection of class */ public function __construct($className, $type, array $advices) { if (strpos($className, AspectContainer::AOP_PROXIED_SUFFIX)) { $originalClass = substr($className, 0, -strlen(AspectContainer::AOP_PROXIED_SUFFIX)); } else { $originalClass = $className; } $this->reflectionClass = new \ReflectionClass($originalClass); parent::__construct($advices); }
/** * Performs weaving of single class if needed * * @param StreamMetaData $metadata Source stream information * @param ParsedClass $class Instance of class to analyze * @param integer $lineOffset Current offset, will be updated to store the last position */ private function processSingleClass(StreamMetaData $metadata, $class, &$lineOffset) { $advices = $this->adviceMatcher->getAdvicesForClass($class); if (!$advices) { // Fast return if there aren't any advices for that class return; } // Sort advices in advance to keep the correct order in cache foreach ($advices as &$typeAdvices) { foreach ($typeAdvices as &$joinpointAdvices) { if (is_array($joinpointAdvices)) { $joinpointAdvices = AbstractJoinpoint::sortAdvices($joinpointAdvices); } } } // Prepare new parent name $newParentName = $class->getShortName() . AspectContainer::AOP_PROXIED_SUFFIX; // Replace original class name with new $metadata->source = $this->adjustOriginalClass($class, $metadata->source, $newParentName); // Prepare child Aop proxy $useStatic = $this->kernel->hasFeature(Features::USE_STATIC_FOR_LSB); $child = $this->kernel->hasFeature(Features::USE_TRAIT) && $class->isTrait() ? new TraitProxy($class, $advices, $useStatic) : new ClassProxy($class, $advices, $useStatic); // Set new parent name instead of original $child->setParentName($newParentName); $contentToInclude = $this->saveProxyToCache($class, $child); // Add child to source $tokenCount = $class->getBroker()->getFileTokens($class->getFileName())->count(); if ($tokenCount - $class->getEndPosition() < 3) { // If it's the last class in a file, just add child source $metadata->source .= $contentToInclude . PHP_EOL; } else { $lastLine = $class->getEndLine() + $lineOffset; // returns the last line of class $dataArray = explode("\n", $metadata->source); $currentClassArray = array_splice($dataArray, 0, $lastLine); $childClassArray = explode("\n", $contentToInclude); $lineOffset += count($childClassArray) + 2; // returns LoC for child class + 2 blank lines $dataArray = array_merge($currentClassArray, array(''), $childClassArray, array(''), $dataArray); $metadata->source = implode("\n", $dataArray); } }
/** * Performs weaving of single class if needed * * @param array|Advisor[] $advisors * @param StreamMetaData $metadata Source stream information * @param ReflectionClass $class Instance of class to analyze * @param integer $lineOffset Current offset, will be updated to store the last position * * @return bool True if was class processed, false otherwise */ private function processSingleClass(array $advisors, StreamMetaData $metadata, ReflectionClass $class, &$lineOffset) { $advices = $this->adviceMatcher->getAdvicesForClass($class, $advisors); if (empty($advices)) { // Fast return if there aren't any advices for that class return false; } // Sort advices in advance to keep the correct order in cache foreach ($advices as &$typeAdvices) { foreach ($typeAdvices as &$joinpointAdvices) { if (is_array($joinpointAdvices)) { $joinpointAdvices = AbstractJoinpoint::sortAdvices($joinpointAdvices); } } } // Prepare new parent name $newParentName = $class->getShortName() . AspectContainer::AOP_PROXIED_SUFFIX; // Replace original class name with new $metadata->source = $this->adjustOriginalClass($class, $metadata->source, $newParentName); // Prepare child Aop proxy $child = $class->isTrait() ? new TraitProxy($class, $advices) : new ClassProxy($class, $advices); // Set new parent name instead of original $child->setParentName($newParentName); $contentToInclude = $this->saveProxyToCache($class, $child); // Add child to source $lastLine = $class->getEndLine() + $lineOffset; // returns the last line of class $dataArray = explode("\n", $metadata->source); $currentClassArray = array_splice($dataArray, 0, $lastLine); $childClassArray = explode("\n", $contentToInclude); $lineOffset += count($childClassArray) + 2; // returns LoC for child class + 2 blank lines $dataArray = array_merge($currentClassArray, array(''), $childClassArray, array(''), $dataArray); $metadata->source = implode("\n", $dataArray); return true; }