/** * Generates a closure that contains PHP code calling an advice. * * @param TypeInfoManagerInterface $manager * @param MethodInfoInterface $method * @return string */ public function generateMethodInterceptionCode(TypeInfoManagerInterface $manager, MethodInfoInterface $method) { $acount = 0; $typeInfo = $method->getDeclaringType(); $init = 'function($jp, $rval = NULL) { '; $code = ' return $jp->getContainer()->get(' . var_export($this->typeName, true); $code .= ')->' . $this->methodName . '('; $advice = $manager->getTypeInfo($this->typeName)->getMethod($this->methodName); foreach ($advice->getParameters() as $i => $param) { if ($i != 0) { $code .= ', '; } if ($param->getName() === $this->subject) { $code .= '$jp->getSubject()'; continue; } if ($param->getName() === $this->returns) { $code .= '$rval'; continue; } if ($this->args !== NULL && false !== ($index = array_search($param->getName(), $this->args, true))) { $code .= '$jp->getArgument(' . var_export($index, true) . ', NULL)'; continue; } $ptypeName = $param->getRequiredType(); if ($ptypeName === NULL) { throw new \RuntimeException(sprintf('Cannot populate parameter "%s" of advice %s without a type-hint', $param->getName(), $this->getInfoSignature($advice))); } $ptype = $manager->getTypeInfo($ptypeName); foreach ($ptype->getSupertypes($manager, true) as $supertype) { if ($supertype->getName() === JoinPointInterface::class) { $code .= '$jp'; continue 2; } } if (preg_match("'\\W@Annotation\\W'i", $ptype->getDocComment())) { $anno = NULL; if ($typeInfo->hasAnnotation($ptype->getName())) { $anno = $typeInfo->getAnnotation($ptype->getName()); } if ($method->hasAnnotation($ptype->getName())) { $anno = $method->getAnnotation($ptype->getName()); } if ($anno === NULL) { $code .= 'NULL'; } else { $init .= 'static $a' . $acount . '; '; $init .= 'if($a' . $acount . ' === NULL) { $a' . $acount; $init .= ' = ' . ParsedAnnotation::compileAnnotation($anno) . '; } '; $code .= '$a' . $acount; $acount++; } continue; } throw new \RuntimeException(sprintf('Cannot populate argument "%s" of advice %s using type-hint %s', $param->getName(), $this->getInfoSignature($advice), $ptype->getName())); } $code .= '); }'; return $init . $code; }