/** * Generates the necessary methods in the class. * * @param \ReflectionClass $originalClass * @param PhpClass $class * @return void */ public function generate(\ReflectionClass $originalClass, PhpClass $class) { $methods = ReflectionUtils::getOverrideableMethods($originalClass, true); // no public, non final methods if (empty($methods)) { return; } if (null !== $this->markerInterface) { $class->setImplementedInterfaces(array_merge($class->getImplementedInterfaces(), array($this->markerInterface))); } $initializer = new PhpProperty(); $initializer->setName($this->prefix . 'lazyInitializer'); $initializer->setVisibility(PhpProperty::VISIBILITY_PRIVATE); $class->setProperty($initializer); $initialized = new PhpProperty(); $initialized->setName($this->prefix . 'initialized'); $initialized->setDefaultValue(false); $initialized->setVisibility(PhpProperty::VISIBILITY_PRIVATE); $class->setProperty($initialized); $initializerSetter = new PhpMethod(); $initializerSetter->setName($this->prefix . 'setLazyInitializer'); $initializerSetter->setBody('$this->' . $this->prefix . 'lazyInitializer = $initializer;'); $parameter = new PhpParameter(); $parameter->setName('initializer'); $parameter->setType('\\CG\\Proxy\\LazyInitializerInterface'); $initializerSetter->addParameter($parameter); $class->setMethod($initializerSetter); $this->addMethods($class, $methods); $initializingMethod = new PhpMethod(); $initializingMethod->setName($this->prefix . 'initialize'); $initializingMethod->setVisibility(PhpMethod::VISIBILITY_PRIVATE); $initializingMethod->setBody($this->writer->reset()->writeln('if (null === $this->' . $this->prefix . 'lazyInitializer) {')->indent()->writeln('throw new \\RuntimeException("' . $this->prefix . 'setLazyInitializer() must be called prior to any other public method on this object.");')->outdent()->write("}\n\n")->writeln('$this->' . $this->prefix . 'lazyInitializer->initializeObject($this);')->writeln('$this->' . $this->prefix . 'initialized = true;')->getContent()); $class->setMethod($initializingMethod); }
public function generate(\ReflectionClass $originalClass, PhpClass $genClass) { $methods = ReflectionUtils::getOverrideableMethods($originalClass); if (null !== $this->filter) { $methods = array_filter($methods, $this->filter); } if (empty($methods)) { return; } if (!empty($this->requiredFile)) { $genClass->addRequiredFile($this->requiredFile); } $interceptorLoader = new PhpProperty(); $interceptorLoader->setName($this->prefix . 'loader')->setVisibility(PhpProperty::VISIBILITY_PRIVATE); $genClass->setProperty($interceptorLoader); $loaderSetter = new PhpMethod(); $loaderSetter->setName($this->prefix . 'setLoader')->setVisibility(PhpMethod::VISIBILITY_PUBLIC)->setBody('$this->' . $this->prefix . 'loader = $loader;'); $genClass->setMethod($loaderSetter); $loaderParam = new PhpParameter(); $loaderParam->setName('loader')->setType('CG\\Proxy\\InterceptorLoaderInterface'); $loaderSetter->addParameter($loaderParam); $interceptorCode = '$ref = new \\ReflectionMethod(%s, %s);' . "\n" . '$interceptors = $this->' . $this->prefix . 'loader->loadInterceptors($ref, $this, array(%s));' . "\n" . '$invocation = new \\CG\\Proxy\\MethodInvocation($ref, $this, array(%s), $interceptors);' . "\n\n" . 'return $invocation->proceed();'; foreach ($methods as $method) { $params = array(); foreach ($method->getParameters() as $param) { $params[] = '$' . $param->name; } $params = implode(', ', $params); $genMethod = PhpMethod::fromReflection($method)->setBody(sprintf($interceptorCode, var_export(ClassUtils::getUserClass($method->class), true), var_export($method->name, true), $params, $params))->setDocblock(null); $genClass->setMethod($genMethod); } }
public function testGetOverridableMethods() { $ref = new \ReflectionClass('CG\\Tests\\Core\\OverridableReflectionTest'); $methods = ReflectionUtils::getOverrideableMethods($ref); $this->assertEquals(4, count($methods)); $methods = array_map(function ($v) { return $v->name; }, $methods); sort($methods); $this->assertEquals(array('a', 'd', 'e', 'h'), $methods); }
/** * @param array<PointcutInterface> $pointcuts * @param array<string,string> $interceptors */ private function processDefinition(Definition $definition, $pointcuts, &$interceptors) { if ($definition->isSynthetic()) { return; } // Symfony 2.6 getFactory method // TODO: Use only getFactory when bumping require to Symfony >= 2.6 if (method_exists($definition, 'getFactory') && $definition->getFactory()) { return; } if (!method_exists($definition, 'getFactory') && ($definition->getFactoryService() || $definition->getFactoryClass())) { return; } if ($originalFilename = $definition->getFile()) { require_once $originalFilename; } if (!class_exists($definition->getClass())) { return; } $class = new \ReflectionClass($definition->getClass()); // check if class is matched $matchingPointcuts = array(); foreach ($pointcuts as $interceptor => $pointcut) { if ($pointcut->matchesClass($class)) { $matchingPointcuts[$interceptor] = $pointcut; } } if (empty($matchingPointcuts)) { return; } $this->addResources($class, $this->container); if ($class->isFinal()) { return; } $classAdvices = array(); foreach (ReflectionUtils::getOverrideableMethods($class) as $method) { if ('__construct' === $method->name) { continue; } $advices = array(); foreach ($matchingPointcuts as $interceptor => $pointcut) { if ($pointcut->matchesMethod($method)) { $advices[] = $interceptor; } } if (empty($advices)) { continue; } $classAdvices[$method->name] = $advices; } if (empty($classAdvices)) { return; } $interceptors[ClassUtils::getUserClass($class->name)] = $classAdvices; $proxyFilename = $this->cacheDir . '/' . str_replace('\\', '-', $class->name) . '.php'; $generator = new InterceptionGenerator(); $generator->setFilter(function (\ReflectionMethod $method) use($classAdvices) { return isset($classAdvices[$method->name]); }); if ($originalFilename) { $relativeOriginalFilename = $this->relativizePath($proxyFilename, $originalFilename); if ($relativeOriginalFilename[0] === '.') { $generator->setRequiredFile(new RelativePath($relativeOriginalFilename)); } else { $generator->setRequiredFile($relativeOriginalFilename); } } $enhancer = new Enhancer($class, array(), array($generator)); $enhancer->setNamingStrategy(new DefaultNamingStrategy('EnhancedProxy' . substr(md5($this->container->getParameter('jms_aop.cache_dir')), 0, 8))); $enhancer->writeClass($proxyFilename); $definition->setFile($proxyFilename); $definition->setClass($enhancer->getClassName($class)); $definition->addMethodCall('__CGInterception__setLoader', array(new Reference('jms_aop.interceptor_loader'))); }