private function parseType($annotations, TokenReflectionClass $tokenizedClass) { $currentNamespace = $tokenizedClass->getNamespaceName(); $currentNamespaceAliases = $tokenizedClass->getNamespaceAliases(); foreach ($annotations as $annotation) { preg_match(self::TYPE_REGEXP, $annotation, $matches); if (!empty($matches[0])) { list($parsedNamespace, $parsedClassName) = $this->parseClass($matches[0]); if ($this->isIgnoredType($parsedClassName)) { continue; } if (empty($parsedNamespace) && isset($currentNamespaceAliases[$parsedClassName])) { return $currentNamespaceAliases[$parsedClassName]; } else { if (isset($currentNamespaceAliases[$parsedNamespace])) { return $currentNamespaceAliases[$parsedNamespace] . '\\' . $parsedClassName; } else { if (class_exists($currentNamespace . '\\' . $parsedClassName)) { return $currentNamespace . '\\' . $parsedClassName; } else { if (class_exists($parsedClassName)) { return $parsedClassName; } } } } } } return null; }
/** * @param ParsedReflectionClass|ParsedReflectionMethod|ParsedReflectionProperty $point * {@inheritdoc} */ public function matches($point) { $expectedClass = $this->expectedClass; if (!$point instanceof $expectedClass) { return false; } $aliases = $point->getNamespaceAliases(); $this->annotationReader->setImports($aliases); $annotation = $this->annotationReader->{$this->annotationMethod}($point, $this->annotationName); return (bool) $annotation; }
/** * {@inheritDoc} */ public function __toString() { $ctor = $this->class->getConstructor(); if ($this->isFieldsIntercepted && (!$ctor || !$ctor->isPrivate())) { $this->addFieldInterceptorsCode($ctor); } $prefix = join(' ', Reflection::getModifierNames($this->class->getModifiers())); $classCode = $this->class->getDocComment() . "\n" . ($prefix ? "{$prefix} " : '') . 'class ' . $this->name . ' extends ' . $this->parentClassName . ($this->interfaces ? ' implements ' . join(', ', $this->interfaces) : '') . "\n" . "{\n" . ($this->traits ? $this->indent('use ' . join(', ', $this->traits) . ';' . "\n") : '') . "\n" . $this->indent(join("\n", $this->propertiesCode)) . "\n" . $this->indent(join("\n", $this->methodsCode)) . "\n" . "}"; return $classCode . PHP_EOL . '\\' . __CLASS__ . "::injectJoinPoints('" . $this->class->name . "'," . var_export($this->advices, true) . ");"; }
public function getInheritanceTree() { $parent_entries = []; $parents = $this->reflection->getParentClassNameList(); $currentNamespace = $this->reflection->getNamespaceName(); if (!empty($parents)) { foreach ($parents as $key => $parent) { $string = ':ref:`'; $string .= str_replace('\\', '-', $parent) . "`"; $parent_entries[] = $string; } } else { return ""; } $refs = join(' => ', $parent_entries); $title = "**Inheritance Hierarchy:**\n"; return "{$title}{$refs}\n\n"; }
/** * Checks the class for possible component and register it in the container if needed * * @param ReflectionClass $class Instance of class reflection * @param ContainerBuilder $container * * @return bool True if component is registered */ protected function checkAndRegisterComponent(ReflectionClass $class, ContainerBuilder $container) { $this->reader->setImports($class->getNamespaceAliases()); $serviceName = str_replace('\\', '.', $class->getName()); $annotation = $this->reader->getClassAnnotation($class, self::ANNOTATION_CLASS); if (!$annotation) { return false; } $definition = $container->register($serviceName, $class->getName()); $constructor = $class->getConstructor(); if ($constructor) { $this->bindConstructorArgs($constructor, $definition, $container); } if ((string) $annotation) { // Make an alias for annotation $container->setAlias($annotation, $serviceName); } return true; }
public function getNamespaceElement() { return '.. php:namespace: ' . str_replace('\\', '\\\\', $this->reflection->getNamespaceName()) . "\n\n"; }
/** * Parses child reflection objects from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionFileNamespace * @throws \TokenReflection\Exception\ParseException If child elements could not be parsed. */ protected function parseChildren(Stream $tokenStream, IReflection $parent) { static $skipped = array(T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => true); $depth = 0; $firstChild = null; while (true) { switch ($tokenStream->getType()) { case T_USE: while (true) { $namespaceName = ''; $alias = null; $tokenStream->skipWhitespaces(true); while (true) { switch ($tokenStream->getType()) { case T_STRING: case T_NS_SEPARATOR: $namespaceName .= $tokenStream->getTokenValue(); break; case T_FUNCTION: // "use function" in 5.6+ break; default: break 2; } $tokenStream->skipWhitespaces(true); } $namespaceName = ltrim($namespaceName, '\\'); if (empty($namespaceName)) { throw new Exception\ParseException($this, $tokenStream, 'Imported namespace name could not be determined.', Exception\ParseException::LOGICAL_ERROR); } elseif ('\\' === substr($namespaceName, -1)) { throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid namespace name "%s".', $namespaceName), Exception\ParseException::LOGICAL_ERROR); } if ($tokenStream->is(T_AS)) { // Alias defined $tokenStream->skipWhitespaces(true); if (!$tokenStream->is(T_STRING)) { throw new Exception\ParseException($this, $tokenStream, sprintf('The imported namespace "%s" seems aliased but the alias name could not be determined.', $namespaceName), Exception\ParseException::LOGICAL_ERROR); } $alias = $tokenStream->getTokenValue(); $tokenStream->skipWhitespaces(true); } else { // No explicit alias if (false !== ($pos = strrpos($namespaceName, '\\'))) { $alias = substr($namespaceName, $pos + 1); } else { $alias = $namespaceName; } } if (isset($this->aliases[$alias])) { throw new Exception\ParseException($this, $tokenStream, sprintf('Namespace alias "%s" already defined.', $alias), Exception\ParseException::LOGICAL_ERROR); } $this->aliases[$alias] = $namespaceName; $type = $tokenStream->getType(); if (';' === $type) { $tokenStream->skipWhitespaces(); break 2; } elseif (',' === $type) { // Next namespace in the current "use" definition continue; } throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } case T_COMMENT: case T_DOC_COMMENT: $docblock = $tokenStream->getTokenValue(); if (preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $docblock)) { array_unshift($this->docblockTemplates, new ReflectionAnnotation($this, $docblock)); } elseif (self::DOCBLOCK_TEMPLATE_END === $docblock) { array_shift($this->docblockTemplates); } $tokenStream->next(); break; case '{': $tokenStream->next(); $depth++; break; case '}': if (0 === $depth--) { break 2; } $tokenStream->next(); break; case null: case T_NAMESPACE: break 2; case T_ABSTRACT: case T_FINAL: case T_CLASS: case T_TRAIT: case T_INTERFACE: $class = new ReflectionClass($tokenStream, $this->getBroker(), $this); $firstChild = $firstChild ?: $class; $className = $class->getName(); if (isset($this->classes[$className])) { if (!$this->classes[$className] instanceof Invalid\ReflectionClass) { $this->classes[$className] = new Invalid\ReflectionClass($className, $this->classes[$className]->getFileName(), $this->getBroker()); } if (!$this->classes[$className]->hasReasons()) { $this->classes[$className]->addReason(new Exception\ParseException($this, $tokenStream, sprintf('Class %s is defined multiple times in the file.', $className), Exception\ParseException::ALREADY_EXISTS)); } } else { $this->classes[$className] = $class; } $tokenStream->next(); break; case T_CONST: $tokenStream->skipWhitespaces(true); do { $constant = new ReflectionConstant($tokenStream, $this->getBroker(), $this); $firstChild = $firstChild ?: $constant; $constantName = $constant->getName(); if (isset($this->constants[$constantName])) { if (!$this->constants[$constantName] instanceof Invalid\ReflectionConstant) { $this->constants[$constantName] = new Invalid\ReflectionConstant($constantName, $this->constants[$constantName]->getFileName(), $this->getBroker()); } if (!$this->constants[$constantName]->hasReasons()) { $this->constants[$constantName]->addReason(new Exception\ParseException($this, $tokenStream, sprintf('Constant %s is defined multiple times in the file.', $constantName), Exception\ParseException::ALREADY_EXISTS)); } } else { $this->constants[$constantName] = $constant; } if ($tokenStream->is(',')) { $tokenStream->skipWhitespaces(true); } else { $tokenStream->next(); } } while ($tokenStream->is(T_STRING)); break; case T_STRING: switch ($tokenStream->getTokenValue()) { case 'define': // definition case // definition case default: break; } $tokenStream->next(); break; case T_FUNCTION: $position = $tokenStream->key() + 1; while (isset($skipped[$type = $tokenStream->getType($position)])) { $position++; } if ('(' === $type) { // Skipping anonymous functions $tokenStream->seek($position)->findMatchingBracket()->skipWhiteSpaces(true); if ($tokenStream->is(T_USE)) { $tokenStream->skipWhitespaces(true)->findMatchingBracket()->skipWhitespaces(true); } $tokenStream->findMatchingBracket()->next(); continue; } $function = new ReflectionFunction($tokenStream, $this->getBroker(), $this); $firstChild = $firstChild ?: $function; $functionName = $function->getName(); if (isset($this->functions[$functionName])) { if (!$this->functions[$functionName] instanceof Invalid\ReflectionFunction) { $this->functions[$functionName] = new Invalid\ReflectionFunction($functionName, $this->functions[$functionName]->getFileName(), $this->getBroker()); } if (!$this->functions[$functionName]->hasReasons()) { $this->functions[$functionName]->addReason(new Exception\ParseException($this, $tokenStream, sprintf('Function %s is defined multiple times in the file.', $functionName), Exception\ParseException::ALREADY_EXISTS)); } } else { $this->functions[$functionName] = $function; } $tokenStream->next(); break; default: $tokenStream->next(); break; } } if ($firstChild) { $this->startPosition = min($this->startPosition, $firstChild->getStartPosition()); } return $this; }
/** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object $className Class name or class instance * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $className, $return = false) { TokenReflection\ReflectionClass::export($broker, $className, $return); }
/** * Tests if method is defined in class in namespace. */ public function testInNamespace() { require_once $this->getFilePath('inNamespace'); $this->getBroker()->processFile($this->getFilePath('inNamespace')); $rfl = new \stdClass(); $class = new \ReflectionClass('TokenReflection\\Test\\MethodInNamespace'); $rfl->internal = $class->getMethod('inNamespace'); $rfl->token = $this->getBroker()->getClass('TokenReflection\\Test\\MethodInNamespace')->getMethod('inNamespace'); $this->assertSame($rfl->internal->inNamespace(), $rfl->token->inNamespace()); $this->assertFalse($rfl->token->inNamespace()); $this->assertSame($rfl->internal->getNamespaceName(), $rfl->token->getNamespaceName()); $this->assertSame('', $rfl->token->getNamespaceName()); $this->assertSame($rfl->internal->getName(), $rfl->token->getName()); $this->assertSame('inNamespace', $rfl->token->getName()); $this->assertSame($rfl->internal->getShortName(), $rfl->token->getShortName()); $this->assertSame('inNamespace', $rfl->token->getShortName()); $rfl = $this->getMethodReflection('noNamespace'); $this->assertSame($rfl->internal->inNamespace(), $rfl->token->inNamespace()); $this->assertFalse($rfl->token->inNamespace()); $this->assertSame($rfl->internal->getNamespaceName(), $rfl->token->getNamespaceName()); $this->assertSame('', $rfl->token->getNamespaceName()); $this->assertSame($rfl->internal->getName(), $rfl->token->getName()); $this->assertSame($this->getMethodName('noNamespace'), $rfl->token->getName()); $this->assertSame($rfl->internal->getShortName(), $rfl->token->getShortName()); $this->assertSame($this->getMethodName('noNamespace'), $rfl->token->getShortName()); }
/** * Save AOP proxy to the separate file anr returns the php source code for inclusion * * @param ParsedClass $class Original class reflection * @param string|ClassProxy $child * * @return string */ private function saveProxyToCache($class, $child) { // Without cache we should rewrite original file if (empty($this->options['cacheDir'])) { return $child; } $cacheDirSuffix = '/_proxies/'; $cacheDir = $this->options['cacheDir'] . $cacheDirSuffix; $fileName = str_replace('\\', '/', $class->getName()) . '.php'; $proxyFileName = $cacheDir . $fileName; $dirname = dirname($proxyFileName); if (!file_exists($dirname)) { mkdir($dirname, 0770, true); } $body = '<?php' . PHP_EOL; $namespace = $class->getNamespaceName(); if ($namespace) { $body .= "namespace {$namespace};" . PHP_EOL . PHP_EOL; } foreach ($class->getNamespaceAliases() as $alias => $fqdn) { $body .= "use {$fqdn} as {$alias};" . PHP_EOL; } $body .= $child; file_put_contents($proxyFileName, $body); return 'include_once AOP_CACHE_DIR . ' . var_export($cacheDirSuffix . $fileName, true) . ';' . PHP_EOL; }
protected function getParser() { return new CommentParser($this->reflection->getDocComment()); }
/** * Parses class modifiers (abstract, final) and class type (class, interface). * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\ReflectionClass $class Defining class * @return \TokenReflection\ReflectionClass * @throws \TokenReflection\Exception\ParseException If the modifiers value cannot be determined. */ private function parseModifiers(Stream $tokenStream, ReflectionClass $class) { while (true) { switch ($tokenStream->getType()) { case T_PUBLIC: case T_VAR: $this->modifiers |= InternalReflectionProperty::IS_PUBLIC; break; case T_PROTECTED: $this->modifiers |= InternalReflectionProperty::IS_PROTECTED; break; case T_PRIVATE: $this->modifiers |= InternalReflectionProperty::IS_PRIVATE; break; case T_STATIC: $this->modifiers |= InternalReflectionProperty::IS_STATIC; break; default: break 2; } $tokenStream->skipWhitespaces(true); } if (InternalReflectionProperty::IS_STATIC === $this->modifiers) { $this->modifiers |= InternalReflectionProperty::IS_PUBLIC; } elseif (0 === $this->modifiers) { $parentProperties = $class->getOwnProperties(); if (empty($parentProperties)) { throw new Exception\ParseException($this, $tokenStream, 'No access level defined and no previous defining class property present.', Exception\ParseException::LOGICAL_ERROR); } $sibling = array_pop($parentProperties); if ($sibling->isPublic()) { $this->modifiers = InternalReflectionProperty::IS_PUBLIC; } elseif ($sibling->isPrivate()) { $this->modifiers = InternalReflectionProperty::IS_PRIVATE; } elseif ($sibling->isProtected()) { $this->modifiers = InternalReflectionProperty::IS_PROTECTED; } else { throw new Exception\ParseException($this, $tokenStream, sprintf('Property sibling "%s" has no access level defined.', $sibling->getName()), Exception\Parse::PARSE_ELEMENT_ERROR); } if ($sibling->isStatic()) { $this->modifiers |= InternalReflectionProperty::IS_STATIC; } } return $this; }
/** * Tests creating class instances without calling the constructor. */ public function testNewInstanceWithoutConstructor() { require_once $this->getFilePath('newInstanceWithoutConstructor'); $this->getBroker()->process($this->getFilePath('newInstanceWithoutConstructor')); $token = $this->getBroker()->getClass('TokenReflection_Test_NewInstanceWithoutConstructor1'); $this->assertInstanceOf('TokenReflection\\ReflectionClass', $token); try { $token->newInstanceWithoutConstructor(); $this->fail('TokenReflection\\Exception\\RuntimeException expected.'); } catch (\Exception $e) { $this->assertInstanceOf('TokenReflection\\Exception\\RuntimeException', $e); if ($e->getCode() !== Exception\RuntimeException::UNSUPPORTED) { throw $e; } } if (PHP_VERSION_ID >= 50400) { // Try the internal reflection $internal = new \ReflectionClass('TokenReflection_Test_NewInstanceWithoutConstructor1'); try { $internal->newInstanceWithoutConstructor(); $this->fail('ReflectionException expected.'); } catch (\Exception $e) { $this->assertInstanceOf('ReflectionException', $e); } } $token = $this->getBroker()->getClass('Exception'); $this->assertInstanceOf('TokenReflection\\Php\\ReflectionClass', $token); try { $token->newInstanceWithoutConstructor(); $this->fail('TokenReflection\\Exception\\RuntimeException expected.'); } catch (\Exception $e) { $this->assertInstanceOf('TokenReflection\\Exception\\RuntimeException', $e); if ($e->getCode() !== Exception\RuntimeException::UNSUPPORTED) { throw $e; } } if (PHP_VERSION_ID >= 50400) { // Try the internal reflection $internal = new \ReflectionClass('Exception'); try { $internal->newInstanceWithoutConstructor(); $this->fail('ReflectionException expected.'); } catch (\Exception $e) { $this->assertInstanceOf('ReflectionException', $e); } } $token = $this->getBroker()->getClass('TokenReflection_Test_NewInstanceWithoutConstructor2'); $internal = new \ReflectionClass('TokenReflection_Test_NewInstanceWithoutConstructor2'); $this->assertInstanceOf('TokenReflection\\ReflectionClass', $token); $instance = $token->newInstanceWithoutConstructor(); $this->assertFalse($instance->check); $instance2 = $token->newInstanceArgs(); $this->assertTrue($instance2->check); if (PHP_VERSION_ID >= 50400) { // Try the internal reflection $this->assertEquals($internal->newInstanceWithoutConstructor(), $token->newInstanceWithoutConstructor()); } }
/** * Creates a new instance using an array of parameters. * * @param array $args Array of constructor parameters * @return object * @throws \TokenReflection\Exception\RuntimeException If the required class does not exist. */ public function newInstanceArgs(array $args = array()) { if (!class_exists($this->name, true)) { throw new Exception\RuntimeException('Could not create an instance; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $reflection = new InternalReflectionClass($this->name); return $reflection->newInstanceArgs($args); }
/** * Gets the annotations applied to a class. * * @param ParsedReflectionClass $class The ReflectionClass of the class from which * the class annotations should be read. * @return array An array of Annotations. */ public function getClassAnnotations(ParsedReflectionClass $class) { $this->parser->setTarget(Target::TARGET_CLASS); return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName()); }
/** * Returns list of introduction advices from advisor * * @param ReflectionClass|ParsedReflectionClass $class Class to inject advices * @param Aop\IntroductionAdvisor $advisor Advisor for class * @param string $advisorId Identifier of advisor * * @return array */ private function getIntroductionFromAdvisor($class, $advisor, $advisorId) { // Do not make introduction for traits if ($class->isTrait()) { return array(); } /** @var $advice Aop\IntroductionInfo */ $advice = $advisor->getAdvice(); $classAdvices[AspectContainer::INTRODUCTION_TRAIT_PREFIX][$advisorId] = $advice; return $classAdvices; }
/** * @param TokenReflection\ReflectionClass|TokenReflection\Invalid\ReflectionClass $ref */ private function loadParentClassesAndInterfacesFromClassReflection($ref) { foreach (array_merge($ref->getParentClasses(), $ref->getInterfaces()) as $parentName => $parentReflection) { /** @var TokenReflection\ReflectionClass $parentReflection */ if ($parentReflection->isInternal()) { if (!isset($this->allClasses[self::INTERNAL_CLASSES][$parentName])) { $this->allClasses[self::INTERNAL_CLASSES][$parentName] = $parentReflection; } } elseif (!$parentReflection->isTokenized()) { if (!isset($this->allClasses[self::NONEXISTENT_CLASSES][$parentName])) { $this->allClasses[self::NONEXISTENT_CLASSES][$parentName] = $parentReflection; } } } }
/** * Parses internal PHP method modifiers (abstract, final, public, ...). * * @param \TokenReflection\ReflectionClass $class Parent class * * @return \TokenReflection\ReflectionMethod */ private function parseInternalModifiers(ReflectionClass $class) { $name = strtolower($this->name); // In PHP 5.3.3+ the ctor can be named only __construct in namespaced classes if ('__construct' === $name || (!$class->inNamespace() || PHP_VERSION_ID < 50303) && strtolower($class->getShortName()) === $name) { $this->modifiers |= self::IS_CONSTRUCTOR; } elseif ('__destruct' === $name) { $this->modifiers |= self::IS_DESTRUCTOR; } elseif ('__clone' === $name) { $this->modifiers |= self::IS_CLONE; } if ($class->isInterface()) { $this->modifiers |= InternalReflectionMethod::IS_ABSTRACT; } else { // Can be called statically, see http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/Zend/zend_API.c?revision=309853&view=markup#l1795 static $notAllowed = array('__clone' => true, '__tostring' => true, '__get' => true, '__set' => true, '__isset' => true, '__unset' => true); if (!$this->isStatic() && !$this->isConstructor() && !$this->isDestructor() && !isset($notAllowed[$name])) { $this->modifiers |= self::IS_ALLOWED_STATIC; } } return $this; }
/** * * @param ReflectionClass $reflection * @return string */ protected static function getObjectType(ReflectionClass $reflection) { return $reflection->isTrait() ? "Trait" : ($reflection->isInterface() ? "Interface" : "Class"); }