protected function buildConstructor(TypeInfoInterface $type, InstrumentationInterface $instrumentation) { $methods = $type->getMethods(); if ($type->hasMethod('__construct')) { // Instance creation checker... $code = 'if(static::$K2TypeName == __CLASS__) { '; $code .= $instrumentation->getInitializationCode(); $code .= ' }'; return $instrumentation->appendMethodCode($type->getMethod('__construct'), $code); } $con = NULL; foreach ($type->getSupertypes($instrumentation->getTypeInfoManager(), true) as $supertype) { if ($supertype->isClass() && $supertype->hasMethod('__construct')) { $con = $supertype->getMethod('__construct'); if ($con->isAbstract()) { continue; } if ($con->isFinal()) { throw new \RuntimeException(sprintf('Unable to compile initializer into type with inherited final constructor: %s', $type->getName())); } break; } } // No inherited constructor found, introduce standard constructor: if ($con === NULL) { if (empty($methods['__construct'])) { $code = 'public function __construct() { '; $code .= 'if(static::$K2TypeName == __CLASS__) { '; $code .= $instrumentation->getInitializationCode(); $code .= ' }'; $code .= '}'; return $instrumentation->introduceCode($code); } } // Inherited constructor found, enhance it by overloading: $code = $instrumentation->buildMethodSignature($con) . ' { '; $code .= 'if(func_num_args() <= ' . count($con->getParameters()) . ') { '; $code .= 'parent::__construct('; foreach ($con->getParameters() as $i => $param) { if ($i != 0) { $code .= ', '; } $code .= '$' . $param->getName(); } $code .= '); } else { '; $code .= 'forward_static_call_array([\'parent\', __FUNCTION__], func_get_args());'; $code .= ' } '; $code .= 'if(static::$K2TypeName == __CLASS__) { '; $code .= $instrumentation->getInitializationCode(); $code .= ' }'; $code .= ' }'; $instrumentation->introduceCode($code); }
protected function interceptMethod(TypeInfoInterface $type, MethodInfoInterface $method, InstrumentationInterface $instrumentation) { $manager = $instrumentation->getTypeInfoManager(); $advices = []; foreach ($this->getAdvisors(Advisor::TARGET_ELEMENT, $manager) as $advisor) { $match = $advisor->matches($manager, $type, $method); if ($match !== NULL) { $advice = clone $advisor->getAdvice(); $interceptor = $advice->getInterceptor(); if ($interceptor instanceof AbstractInterceptor) { $interceptor->setSubject($match->getTarget()); $interceptor->setArgs($match->getArgs()); $interceptor->setReturns($match->getReturns()); } $advices[] = $advice; } } if (empty($advices)) { return; } $code = ''; if (!$type->is($method->getDeclaringType())) { if ($method->isFinal() || $method->isPrivate()) { return; } $code = $instrumentation->buildMethodSignature($method) . ' { '; } $code .= 'if(static::class == __CLASS__ && \\KoolKode\\Aop\\Advice::isAdviceEnabled()) { '; $code .= 'static $__i; '; $code .= 'if($__i === NULL) { $__i = ['; $sorter = function (Advice $a, Advice $b) { $o1 = $a->getOrder(); $o2 = $b->getOrder(); if ($o1 === $o2) { return 0; } return $o1 > $o2 ? -1 : 1; }; $merger = function (Advice $advice) use($manager, $method) { $interceptor = $advice->getInterceptor(); if ($interceptor instanceof ContainerInterceptor) { return $interceptor->generateMethodInterceptionCode($manager, $method); } return $interceptor->exportCode(); }; $before = []; $around = []; $after = []; foreach ($advices as $advice) { if ($advice instanceof BeforeAdvice) { $before[] = $advice; } elseif ($advice instanceof AroundAdvice) { $around[] = $advice; } elseif ($advice instanceof AfterAdvice) { $after[] = $advice; } } usort($before, $sorter); usort($around, $sorter); usort($after, function (Advice $a, Advice $b) use($sorter) { return $sorter($b, $a); }); $code .= '[' . implode(', ', array_map($merger, $before)) . '], '; $code .= '[' . implode(', ', array_map($merger, $after)) . '], '; if (empty($around)) { $code .= '[]'; } else { $code .= '[1 => ' . implode(', ', array_map($merger, $around)) . ']'; } $code .= ']; } '; if ($method->isReturnReference()) { $code .= 'unset($__r); $__r = '; } else { $code .= 'return '; } $code .= '(new \\KoolKode\\Aop\\MethodInvocation(\\KoolKode\\K2\\Kernel::getContainer(), '; $code .= '$this, __CLASS__ , __FUNCTION__, '; $code .= '\\func_get_args(), $__i))->proceed();'; if ($method->isReturnReference()) { $code .= ' return $__r;'; } $code .= ' }'; if (!$type->is($method->getDeclaringType())) { if ($method->isReturnReference()) { $code .= ' unset($__r); $__r = call_user_func_array(['; $code .= var_export($method->getDeclaringType()->getName(), true); $code .= ', __FUNCTION__], func_get_args()); return $__r;'; } else { $code .= ' return call_user_func_array(['; $code .= var_export($method->getDeclaringType()->getName(), true); $code .= ', __FUNCTION__], func_get_args());'; } $instrumentation->introduceCode($code . ' }'); } else { $instrumentation->prependMethodCode($method, $code); } return true; }