/** * Renders the PHP code for this Proxy Method * * @return string PHP code */ public function render() { $methodDocumentation = $this->buildMethodDocumentation($this->fullOriginalClassName, $this->methodName); $methodParametersCode = $this->methodParametersCode !== '' ? $this->methodParametersCode : $this->buildMethodParametersCode($this->fullOriginalClassName, $this->methodName); $callParentMethodCode = $this->buildCallParentMethodCode($this->fullOriginalClassName, $this->methodName); $staticKeyword = $this->reflectionService->isMethodStatic($this->fullOriginalClassName, $this->methodName) ? 'static ' : ''; $visibility = $this->visibility === null ? $this->getMethodVisibilityString() : $this->visibility; $returnType = $this->reflectionService->getMethodDeclaredReturnType($this->fullOriginalClassName, $this->methodName); $returnTypeDeclaration = $returnType !== null ? ' : ' . $returnType : ''; $code = ''; if ($this->addedPreParentCallCode !== '' || $this->addedPostParentCallCode !== '' || $this->methodBody !== '') { $code = "\n" . $methodDocumentation . ' ' . $staticKeyword . $visibility . ' function ' . $this->methodName . '(' . $methodParametersCode . "){$returnTypeDeclaration}\n {\n"; if ($this->methodBody !== '') { $code .= "\n" . $this->methodBody . "\n"; } else { $code .= $this->addedPreParentCallCode; if ($this->addedPostParentCallCode !== '') { $code .= ' $result = ' . ($callParentMethodCode === '' ? "NULL;\n" : $callParentMethodCode); $code .= $this->addedPostParentCallCode; $code .= " return \$result;\n"; } else { $code .= $callParentMethodCode === '' ? '' : ' return ' . $callParentMethodCode . ";\n"; } } $code .= " }\n"; } return $code; }
/** * Traverses all aspect containers, their aspects and their advisors and adds the * methods and their advices to the (usually empty) array of intercepted methods. * * @param array &$interceptedMethods An array (empty or not) which contains the names of the intercepted methods and additional information * @param array $methods An array of class and method names which are matched against the pointcut (class name = name of the class or interface the method was declared) * @param string $targetClassName Name of the class the pointcut should match with * @param array &$aspectContainers All aspects to take into consideration * @return void */ protected function addAdvicedMethodsToInterceptedMethods(array &$interceptedMethods, array $methods, $targetClassName, array &$aspectContainers) { $pointcutQueryIdentifier = 0; foreach ($aspectContainers as $aspectContainer) { if (!$aspectContainer->getCachedTargetClassNameCandidates()->hasClassName($targetClassName)) { continue; } foreach ($aspectContainer->getAdvisors() as $advisor) { $pointcut = $advisor->getPointcut(); foreach ($methods as $method) { list($methodDeclaringClassName, $methodName) = $method; if ($this->reflectionService->isMethodFinal($targetClassName, $methodName)) { continue; } if ($this->reflectionService->isMethodStatic($targetClassName, $methodName)) { continue; } if ($pointcut->matches($targetClassName, $methodName, $methodDeclaringClassName, $pointcutQueryIdentifier)) { $advice = $advisor->getAdvice(); $interceptedMethods[$methodName]['groupedAdvices'][get_class($advice)][] = ['advice' => $advice, 'runtimeEvaluationsClosureCode' => $pointcut->getRuntimeEvaluationsClosureCode()]; $interceptedMethods[$methodName]['declaringClassName'] = $methodDeclaringClassName; } $pointcutQueryIdentifier++; } } } }
/** * Compile the result of methods marked with CompileStatic into the proxy class * * @param string $className * @param ProxyClass $proxyClass * @return void * @throws ObjectException */ protected function compileStaticMethods($className, ProxyClass $proxyClass) { $methodNames = $this->reflectionService->getMethodsAnnotatedWith($className, Flow\CompileStatic::class); foreach ($methodNames as $methodName) { if (!$this->reflectionService->isMethodStatic($className, $methodName)) { throw new ObjectException(sprintf('The method %s:%s() is annotated CompileStatic so it must be static', $className, $methodName), 1476348303); } if ($this->reflectionService->isMethodPrivate($className, $methodName)) { throw new ObjectException(sprintf('The method %s:%s() is annotated CompileStatic so it must not be private', $className, $methodName), 1476348306); } $reflectedMethod = new MethodReflection($className, $methodName); $reflectedMethod->setAccessible(true); $value = $reflectedMethod->invoke(null, $this->objectManager); $compiledResult = var_export($value, true); $compiledMethod = $proxyClass->getMethod($methodName); $compiledMethod->setMethodBody('return ' . $compiledResult . ';'); } }