getBroker()->getClass($this->declaringClassName); } /** * Returns the name of the declaring class. * * @return string */ public function getDeclaringClassName() { return $this->declaringClassName; } /** * Returns the property default value. * * @return mixed */ public function getDefaultValue() { if (is_array($this->defaultValueDefinition)) { $this->defaultValue = Resolver::getValueDefinition($this->defaultValueDefinition, $this); $this->defaultValueDefinition = Resolver::getSourceCode($this->defaultValueDefinition); } return $this->defaultValue; } /** * Returns the part of the source code defining the property default value. * * @return string */ public function getDefaultValueDefinition() { return is_array($this->defaultValueDefinition) ? Resolver::getSourceCode($this->defaultValueDefinition) : $this->defaultValueDefinition; } /** * Returns the property value for a particular class instance. * * @param object $object * @return mixed * @throws \TokenReflection\Exception\RuntimeException If it is not possible to return the property value. */ public function getValue($object) { $declaringClass = $this->getDeclaringClass(); if (!$declaringClass->isInstance($object)) { throw new Exception\RuntimeException('The given class is not an instance or subclass of the current class.', Exception\RuntimeException::INVALID_ARGUMENT, $this); } if ($this->isPublic()) { return $object->{$this->name}; } elseif ($this->isAccessible()) { $refClass = new InternalReflectionClass($object); $refProperty = $refClass->getProperty($this->name); $refProperty->setAccessible(true); $value = $refProperty->getValue($object); $refProperty->setAccessible(false); return $value; } throw new Exception\RuntimeException('Only public and accessible properties can return their values.', Exception\RuntimeException::NOT_ACCESSBILE, $this); } /** * Returns if the property was created at compile time. * * All properties in the source code are. * * @return boolean */ public function isDefault() { return true; } /** * Returns property modifiers. * * @return integer */ public function getModifiers() { if (false === $this->modifiersComplete) { $declaringClass = $this->getDeclaringClass(); $declaringClassParent = $declaringClass->getParentClass(); if ($declaringClassParent && $declaringClassParent->hasProperty($this->name)) { $property = $declaringClassParent->getProperty($this->name); if (($this->isPublic() && !$property->isPublic()) || ($this->isProtected() && $property->isPrivate())) { $this->modifiers |= self::ACCESS_LEVEL_CHANGED; } } $this->modifiersComplete = ($this->modifiers & self::ACCESS_LEVEL_CHANGED) || $declaringClass->isComplete(); } return $this->modifiers; } /** * Returns if the property is private. * * @return boolean */ public function isPrivate() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_PRIVATE); } /** * Returns if the property is protected. * * @return boolean */ public function isProtected() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_PROTECTED); } /** * Returns if the property is public. * * @return boolean */ public function isPublic() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_PUBLIC); } /** * Returns if the poperty is static. * * @return boolean */ public function isStatic() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_STATIC); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "Property [ %s%s%s%s%s\$%s ]\n", $this->isStatic() ? '' : ' ', $this->isPublic() ? 'public ' : '', $this->isPrivate() ? 'private ' : '', $this->isProtected() ? 'protected ' : '', $this->isStatic() ? 'static ' : '', $this->getName() ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object $class Class name or class instance * @param string $property Property name * @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, $class, $property, $return = false) { $className = is_object($class) ? get_class($class) : $class; $propertyName = $property; $class = $broker->getClass($className); if ($class instanceof Invalid\ReflectionClass) { throw new Exception\RuntimeException('Class is invalid.', Exception\RuntimeException::UNSUPPORTED); } elseif ($class instanceof Dummy\ReflectionClass) { throw new Exception\RuntimeException(sprintf('Class %s does not exist.', $className), Exception\RuntimeException::DOES_NOT_EXIST); } $property = $class->getProperty($propertyName); if ($return) { return $property->__toString(); } echo $property->__toString(); } /** * Returns if the property is set accessible. * * @return boolean */ public function isAccessible() { return $this->accessible; } /** * Sets a property to be accessible or not. * * @param boolean $accessible If the property should be accessible. */ public function setAccessible($accessible) { $this->accessible = (bool) $accessible; } /** * Sets the property default value. * * @param mixed $value */ public function setDefaultValue($value) { $this->defaultValue = $value; $this->defaultValueDefinition = var_export($value, true); } /** * Sets value of a property for a particular class instance. * * @param object $object Class instance * @param mixed $value Poperty value * @throws \TokenReflection\Exception\RuntimeException If it is not possible to set the property value. */ public function setValue($object, $value) { $declaringClass = $this->getDeclaringClass(); if (!$declaringClass->isInstance($object)) { throw new Exception\RuntimeException('Instance of or subclass expected.', Exception\RuntimeException::INVALID_ARGUMENT, $this); } if ($this->isPublic()) { $object->{$this->name} = $value; } elseif ($this->isAccessible()) { $refClass = new InternalReflectionClass($object); $refProperty = $refClass->getProperty($this->name); $refProperty->setAccessible(true); $refProperty->setValue($object, $value); $refProperty->setAccessible(false); if ($this->isStatic()) { $this->setDefaultValue($value); } } else { throw new Exception\RuntimeException('Only public and accessible properties can be set.', Exception\RuntimeException::NOT_ACCESSBILE, $this); } } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->getDeclaringClass()->getNamespaceAliases(); } /** * Creates a property alias for the given class. * * @param \TokenReflection\ReflectionClass $parent New parent class * @return \TokenReflection\ReflectionProperty */ public function alias(ReflectionClass $parent) { $property = clone $this; $property->declaringClassName = $parent->getName(); return $property; } /** * Returns the defining trait. * * @return \TokenReflection\IReflectionClass|null */ public function getDeclaringTrait() { return null === $this->declaringTraitName ? null : $this->getBroker()->getClass($this->declaringTraitName); } /** * Returns the declaring trait name. * * @return string|null */ public function getDeclaringTraitName() { return $this->declaringTraitName; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return sprintf('%s::$%s', $this->declaringClassName ?: $this->declaringTraitName, $this->name); } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement * @throws \TokenReflection\Exception\Parse If an invalid parent reflection object was provided. */ protected function processParent(IReflection $parent, Stream $tokenStream) { if (!$parent instanceof ReflectionClass) { throw new Exception\ParseException($this, $tokenStream, 'The parent object has to be an instance of TokenReflection\ReflectionClass.', Exception\ParseException::INVALID_PARENT); } $this->declaringClassName = $parent->getName(); if ($parent->isTrait()) { $this->declaringTraitName = $parent->getName(); } return parent::processParent($parent, $tokenStream); } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionProperty */ protected function parse(Stream $tokenStream, IReflection $parent) { $this->parseModifiers($tokenStream, $parent); if (false === $this->docComment->getDocComment()) { $this->parseDocComment($tokenStream, $parent); } return $this->parseName($tokenStream) ->parseDefaultValue($tokenStream); } /** * 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; } /** * Parses the property name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionProperty * @throws \TokenReflection\Exception\ParseException If the property name could not be determined. */ protected function parseName(Stream $tokenStream) { if (!$tokenStream->is(T_VARIABLE)) { throw new Exception\ParseException($this, $tokenStream, 'The property name could not be determined.', Exception\ParseException::LOGICAL_ERROR); } $this->name = substr($tokenStream->getTokenValue(), 1); $tokenStream->skipWhitespaces(true); return $this; } /** * Parses the propety default value. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionProperty * @throws \TokenReflection\Exception\ParseException If the property default value could not be determined. */ private function parseDefaultValue(Stream $tokenStream) { $type = $tokenStream->getType(); if (';' === $type || ',' === $type) { // No default value return $this; } if ('=' === $type) { $tokenStream->skipWhitespaces(true); } $level = 0; while (null !== ($type = $tokenStream->getType())) { switch ($type) { case ',': if (0 !== $level) { break; } case ';': break 2; case ')': case ']': case '}': $level--; break; case '(': case '{': case '[': $level++; break; default: break; } $this->defaultValueDefinition[] = $tokenStream->current(); $tokenStream->next(); } if (',' !== $type && ';' !== $type) { throw new Exception\ParseException($this, $tokenStream, 'The property default value is not terminated properly. Expected "," or ";".', Exception\ParseException::UNEXPECTED_TOKEN); } return $this; } }