mirror of
https://github.com/barryvdh/ReflectionDocBlock.git
synced 2026-08-18 01:57:13 +00:00
Introduce Types
phpDocumentor is capable of representing a whole series of types, more than PHP supports in fact, and this commit represents those types and a Resolver that is capable of taking a type Expression and resolving that to a series of Value Objects representing those types.
This commit is contained in:
committed by
Mike van Riel
parent
fab7169255
commit
b54671f51f
+26
-2
@@ -10,12 +10,21 @@
|
||||
* @link http://phpdoc.org
|
||||
*/
|
||||
|
||||
|
||||
namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Fqsen;
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
class Array_ implements Type
|
||||
/**
|
||||
* Represents an array type as described in the PSR-5, the PHPDoc Standard.
|
||||
*
|
||||
* An array can be represented in two forms:
|
||||
*
|
||||
* 1. Untyped (`array`), where the key and value type is unknown and hence classified as 'Mixed'.
|
||||
* 2. Types (`string[]`), where the value type is provided by preceding an opening and closing square bracket with a
|
||||
* type name.
|
||||
*/
|
||||
final class Array_ implements Type
|
||||
{
|
||||
/** @var Type */
|
||||
private $valueType;
|
||||
@@ -23,6 +32,12 @@ class Array_ implements Type
|
||||
/** @var Type */
|
||||
private $keyType;
|
||||
|
||||
/**
|
||||
* Initializes this representation of an array with the given Type or Fqsen.
|
||||
*
|
||||
* @param Type $valueType
|
||||
* @param Type $keyType
|
||||
*/
|
||||
public function __construct(Type $valueType = null, Type $keyType = null)
|
||||
{
|
||||
if ($keyType === null) {
|
||||
@@ -37,6 +52,8 @@ class Array_ implements Type
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type for the keys of this array.
|
||||
*
|
||||
* @return Type
|
||||
*/
|
||||
public function getKeyType()
|
||||
@@ -45,6 +62,8 @@ class Array_ implements Type
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the keys of this array.
|
||||
*
|
||||
* @return Type
|
||||
*/
|
||||
public function getValueType()
|
||||
@@ -52,6 +71,11 @@ class Array_ implements Type
|
||||
return $this->valueType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->valueType instanceof Mixed) {
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing a Boolean type.
|
||||
*/
|
||||
final class Boolean implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'bool';
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing a Callable type.
|
||||
*/
|
||||
final class Callable_ implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'callable';
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of phpDocumentor.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @copyright 2010-2015 Mike van Riel<[email protected]>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link http://phpdoc.org
|
||||
*/
|
||||
|
||||
namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Types\Resolver;
|
||||
use phpDocumentor\Reflection\DocBlock\Context;
|
||||
|
||||
/**
|
||||
* Collection
|
||||
*/
|
||||
class Collection extends \ArrayObject
|
||||
{
|
||||
/** @var string Definition of the OR operator for types */
|
||||
const OPERATOR_OR = '|';
|
||||
|
||||
/**
|
||||
* Current invoking location.
|
||||
*
|
||||
* This is used to prepend to type with a relative location.
|
||||
* May also be 'default' or 'global', in which case they are ignored.
|
||||
*
|
||||
* @var Context
|
||||
*/
|
||||
protected $context = null;
|
||||
/**
|
||||
* @var Resolver
|
||||
*/
|
||||
private $resolver;
|
||||
|
||||
/**
|
||||
* Registers the namespace and aliases; uses that to add and expand the given types.
|
||||
*
|
||||
* @param string[] $types Array containing a list of types to add to this container.
|
||||
* @param Context $context
|
||||
* @param Resolver $resolver
|
||||
*/
|
||||
public function __construct(array $types = array(), Context $context = null, Resolver $resolver = null)
|
||||
{
|
||||
$this->context = $context ?: new Context('');
|
||||
$this->resolver = $resolver ?: new Resolver();
|
||||
|
||||
foreach ($types as $type) {
|
||||
$this->add($type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current invoking location.
|
||||
*
|
||||
* @return Context
|
||||
*/
|
||||
public function getContext()
|
||||
{
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new type to the collection and expands it if it contains a
|
||||
* relative namespace.
|
||||
*
|
||||
* If a class in the type contains a relative namespace than this collection
|
||||
* will try to expand that into a FQCN.
|
||||
*
|
||||
* @param string $type A 'Type' as defined in the phpDocumentor
|
||||
* documentation.
|
||||
*
|
||||
* @throws \InvalidArgumentException if a non-string argument is passed.
|
||||
*
|
||||
* @see http://phpdoc.org/docs/latest/for-users/types.html for the
|
||||
* definition of a type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($type)
|
||||
{
|
||||
if (!is_string($type)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'A type should be represented by a string, received: '
|
||||
. var_export($type, true)
|
||||
);
|
||||
}
|
||||
|
||||
// separate the type by the OR operator
|
||||
$type_parts = explode(self::OPERATOR_OR, $type);
|
||||
foreach ($type_parts as $part) {
|
||||
$expanded_type = $this->resolver->resolve($part, $this->context);
|
||||
if ($expanded_type) {
|
||||
$this[] = $expanded_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the collection.
|
||||
*
|
||||
* @return string The resolved types across the collection, separated with
|
||||
* {@link self::OPERATOR_OR}.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return implode(self::OPERATOR_OR, $this->getArrayCopy());
|
||||
}
|
||||
}
|
||||
+26
-4
@@ -10,29 +10,44 @@
|
||||
* @link http://phpdoc.org
|
||||
*/
|
||||
|
||||
|
||||
namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Fqsen;
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing a Compound Type.
|
||||
*
|
||||
* A Compound Type is not so much a special keyword or object reference but is a series of Types that are separated
|
||||
* using an OR operator (`|`). This combination of types signifies that whatever is associated with this compound type
|
||||
* may contain a value with any of the given types.
|
||||
*/
|
||||
final class Compound implements Type
|
||||
{
|
||||
/** @var Type[] */
|
||||
private $types = [];
|
||||
|
||||
/**
|
||||
* @param Type[]|Fqsen[] $types
|
||||
* Initializes a compound type (i.e. `string|int`) and tests if the provided types all implement the Type interface.
|
||||
*
|
||||
* @param Type[] $types
|
||||
*/
|
||||
public function __construct($types)
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
if (!$type instanceof Type) {
|
||||
throw new \InvalidArgumentException('A compound type can only have other types as elements');
|
||||
}
|
||||
}
|
||||
|
||||
$this->types = $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type at the given index.
|
||||
*
|
||||
* @param integer $index
|
||||
*
|
||||
* @return null|Type|Fqsen
|
||||
* @return Type|null
|
||||
*/
|
||||
public function get($index)
|
||||
{
|
||||
@@ -44,6 +59,8 @@ final class Compound implements Type
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if this compound type has a type with the given index.
|
||||
*
|
||||
* @param integer $index
|
||||
*
|
||||
* @return bool
|
||||
@@ -53,6 +70,11 @@ final class Compound implements Type
|
||||
return isset($this->types[$index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return implode('|', $this->types);
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing a Float.
|
||||
*/
|
||||
final class Float implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'float';
|
||||
|
||||
@@ -16,6 +16,11 @@ use phpDocumentor\Reflection\Type;
|
||||
|
||||
final class Integer implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'int';
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing an unknown, or mixed, type.
|
||||
*/
|
||||
final class Mixed implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'mixed';
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing a null value or type.
|
||||
*/
|
||||
final class Null_ implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'null';
|
||||
|
||||
@@ -12,12 +12,59 @@
|
||||
|
||||
namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Fqsen;
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing an object.
|
||||
*
|
||||
* An object can be either typed or untyped. When an object is typed it means that it has an identifier, the FQSEN,
|
||||
* pointing to an element in PHP. Object types that are untyped do not refer to a specific class but represent objects
|
||||
* in general.
|
||||
*/
|
||||
final class Object_ implements Type
|
||||
{
|
||||
/** @var Fqsen|null */
|
||||
private $fqsen;
|
||||
|
||||
/**
|
||||
* Initializes this object with an optional FQSEN, if not provided this object is considered 'untyped'.
|
||||
*
|
||||
* @param Fqsen $fqsen
|
||||
*/
|
||||
public function __construct(Fqsen $fqsen = null)
|
||||
{
|
||||
if (strpos((string)$fqsen, '::') !== false || strpos((string)$fqsen, '()') !== false) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Object types can only refer to a class, interface or trait but a method, function, constant or '
|
||||
. 'property was received: ' . (string)$fqsen
|
||||
);
|
||||
}
|
||||
|
||||
$this->fqsen = $fqsen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FQSEN associated with this object.
|
||||
*
|
||||
* @return Fqsen|null
|
||||
*/
|
||||
public function getFqsen()
|
||||
{
|
||||
return $this->fqsen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->fqsen) {
|
||||
return (string)$this->fqsen;
|
||||
}
|
||||
|
||||
return 'object';
|
||||
}
|
||||
}
|
||||
|
||||
+32
-6
@@ -65,7 +65,7 @@ class Resolver
|
||||
* @uses Context::getNamespaceAliases() to check whether the first part of the relative type name should not be
|
||||
* replaced with another namespace.
|
||||
*
|
||||
* @return Fqsen|Type|null
|
||||
* @return Type|null
|
||||
*/
|
||||
public function resolve($type, Context $context)
|
||||
{
|
||||
@@ -101,6 +101,32 @@ class Resolver
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a keyword to the list of Keywords and associates it with a specific Value Object.
|
||||
*
|
||||
* @param string $keyword
|
||||
* @param string $typeClassName
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addKeyword($keyword, $typeClassName)
|
||||
{
|
||||
if (!class_exists($typeClassName)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class'
|
||||
. ' but we could not find the class ' . $typeClassName
|
||||
);
|
||||
}
|
||||
|
||||
if (!in_array(Type::class, class_implements($typeClassName))) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The class "' . $typeClassName . '" must implement the interface "phpDocumentor\Reflection\Type"'
|
||||
);
|
||||
}
|
||||
|
||||
$this->keywords[$keyword] = $typeClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether the given type represents an array.
|
||||
*
|
||||
@@ -193,11 +219,11 @@ class Resolver
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Fqsen
|
||||
* @return Object_
|
||||
*/
|
||||
private function resolveFqsen($type)
|
||||
{
|
||||
return new Fqsen($type);
|
||||
return new Object_(new Fqsen($type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,7 +233,7 @@ class Resolver
|
||||
* @param string $type
|
||||
* @param Context $context
|
||||
*
|
||||
* @return Fqsen
|
||||
* @return Object_
|
||||
*/
|
||||
private function resolvePartialStructuralElementName($type, Context $context)
|
||||
{
|
||||
@@ -222,12 +248,12 @@ class Resolver
|
||||
$namespace .= self::OPERATOR_NAMESPACE;
|
||||
}
|
||||
|
||||
return new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type);
|
||||
return new Object_(new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type));
|
||||
}
|
||||
|
||||
$typeParts[0] = $namespaceAliases[$typeParts[0]];
|
||||
|
||||
return new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts));
|
||||
return new Object_(new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing the 'resource' Type.
|
||||
*/
|
||||
final class Resource implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'resource';
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
class Scalar implements Type
|
||||
/**
|
||||
* Value Object representing the 'scalar' pseudo-type, which is either a string, integer, float or boolean.
|
||||
*/
|
||||
final class Scalar implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'scalar';
|
||||
|
||||
@@ -14,8 +14,18 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing the 'self' type.
|
||||
*
|
||||
* Self, as a Type, represents the class in which the associated element was defined.
|
||||
*/
|
||||
final class Self_ implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'self';
|
||||
|
||||
@@ -14,8 +14,23 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing the 'static' type.
|
||||
*
|
||||
* Self, as a Type, represents the class in which the associated element was called. This differs from self as self does
|
||||
* not take inheritance into account but static means that the return type is always that of the class of the called
|
||||
* element.
|
||||
*
|
||||
* See the documentation on late static binding in the PHP Documentation for more information on the difference between
|
||||
* static and self.
|
||||
*/
|
||||
final class Static_ implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'static';
|
||||
|
||||
@@ -14,8 +14,16 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing the type 'string'.
|
||||
*/
|
||||
final class String implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'string';
|
||||
|
||||
@@ -14,8 +14,19 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing the '$this' pseudo-type.
|
||||
*
|
||||
* $this, as a Type, represents the instance of the class associated with the element as it was called. $this is
|
||||
* commonly used when documenting fluent interfaces since it represents that the same object is returned.
|
||||
*/
|
||||
final class This implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return '$this';
|
||||
|
||||
@@ -14,8 +14,19 @@ namespace phpDocumentor\Reflection\Types;
|
||||
|
||||
use phpDocumentor\Reflection\Type;
|
||||
|
||||
/**
|
||||
* Value Object representing the pseudo-type 'void'.
|
||||
*
|
||||
* Void is generally only used when working with return types as it signifies that the method intentionally does not
|
||||
* return any value.
|
||||
*/
|
||||
final class Void implements Type
|
||||
{
|
||||
/**
|
||||
* Returns a rendered output of the Type as it would be used in a DocBlock.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'void';
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* phpDocumentor
|
||||
*
|
||||
* PHP Version 5.3
|
||||
*
|
||||
* @author Mike van Riel <[email protected]>
|
||||
* @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link http://phpdoc.org
|
||||
*/
|
||||
|
||||
namespace phpDocumentor\Reflection\DocBlock\Type;
|
||||
|
||||
use phpDocumentor\Reflection\DocBlock\Context;
|
||||
|
||||
/**
|
||||
* Collection
|
||||
*
|
||||
* @author Mike van Riel <[email protected]>
|
||||
* @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link http://phpdoc.org
|
||||
*/
|
||||
class Collection extends \ArrayObject
|
||||
{
|
||||
/** @var string Definition of the OR operator for types */
|
||||
const OPERATOR_OR = '|';
|
||||
|
||||
/** @var string Definition of the ARRAY operator for types */
|
||||
const OPERATOR_ARRAY = '[]';
|
||||
|
||||
/** @var string Definition of the NAMESPACE operator in PHP */
|
||||
const OPERATOR_NAMESPACE = '\\';
|
||||
|
||||
/** @var string[] List of recognized keywords */
|
||||
protected static $keywords = array(
|
||||
'string', 'int', 'integer', 'bool', 'boolean', 'float', 'double',
|
||||
'object', 'mixed', 'array', 'resource', 'void', 'null', 'scalar',
|
||||
'callback', 'callable', 'false', 'true', 'self', '$this', 'static'
|
||||
);
|
||||
|
||||
/**
|
||||
* Current invoking location.
|
||||
*
|
||||
* This is used to prepend to type with a relative location.
|
||||
* May also be 'default' or 'global', in which case they are ignored.
|
||||
*
|
||||
* @var Context
|
||||
*/
|
||||
protected $context = null;
|
||||
|
||||
/**
|
||||
* Registers the namespace and aliases; uses that to add and expand the
|
||||
* given types.
|
||||
*
|
||||
* @param string[] $types Array containing a list of types to add to this
|
||||
* container.
|
||||
* @param Context $location The current invoking location.
|
||||
*/
|
||||
public function __construct(
|
||||
array $types = array(),
|
||||
Context $context = null
|
||||
) {
|
||||
$this->context = null === $context ? new Context() : $context;
|
||||
|
||||
foreach ($types as $type) {
|
||||
$this->add($type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current invoking location.
|
||||
*
|
||||
* @return Context
|
||||
*/
|
||||
public function getContext()
|
||||
{
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new type to the collection and expands it if it contains a
|
||||
* relative namespace.
|
||||
*
|
||||
* If a class in the type contains a relative namespace than this collection
|
||||
* will try to expand that into a FQCN.
|
||||
*
|
||||
* @param string $type A 'Type' as defined in the phpDocumentor
|
||||
* documentation.
|
||||
*
|
||||
* @throws \InvalidArgumentException if a non-string argument is passed.
|
||||
*
|
||||
* @see http://phpdoc.org/docs/latest/for-users/types.html for the
|
||||
* definition of a type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($type)
|
||||
{
|
||||
if (!is_string($type)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'A type should be represented by a string, received: '
|
||||
.var_export($type, true)
|
||||
);
|
||||
}
|
||||
|
||||
// separate the type by the OR operator
|
||||
$type_parts = explode(self::OPERATOR_OR, $type);
|
||||
foreach ($type_parts as $part) {
|
||||
$expanded_type = $this->expand($part);
|
||||
if ($expanded_type) {
|
||||
$this[] = $expanded_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the collection.
|
||||
*
|
||||
* @return string The resolved types across the collection, separated with
|
||||
* {@link self::OPERATOR_OR}.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return implode(self::OPERATOR_OR, $this->getArrayCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the given type and returns the FQCN variant.
|
||||
*
|
||||
* When a type is provided this method checks whether it is not a keyword or
|
||||
* Fully Qualified Class Name. If so it will use the given namespace and
|
||||
* aliases to expand the type to a FQCN representation.
|
||||
*
|
||||
* This method only works as expected if the namespace and aliases are set;
|
||||
* no dynamic reflection is being performed here.
|
||||
*
|
||||
* @param string $type The relative or absolute type.
|
||||
*
|
||||
* @uses getNamespace to determine with what to prefix the type name.
|
||||
* @uses getNamespaceAliases to check whether the first part of the relative
|
||||
* type name should not be replaced with another namespace.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function expand($type)
|
||||
{
|
||||
$type = trim($type);
|
||||
if (!$type) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($this->isTypeAnArray($type)) {
|
||||
return $this->expand(substr($type, 0, -2)) . self::OPERATOR_ARRAY;
|
||||
}
|
||||
|
||||
if ($this->isRelativeType($type) && !$this->isTypeAKeyword($type)) {
|
||||
$type_parts = explode(self::OPERATOR_NAMESPACE, $type, 2);
|
||||
|
||||
$namespace_aliases = $this->context->getNamespaceAliases();
|
||||
// if the first segment is not an alias; prepend namespace name and
|
||||
// return
|
||||
if (!isset($namespace_aliases[$type_parts[0]])) {
|
||||
$namespace = $this->context->getNamespace();
|
||||
if ('' !== $namespace) {
|
||||
$namespace .= self::OPERATOR_NAMESPACE;
|
||||
}
|
||||
return self::OPERATOR_NAMESPACE . $namespace . $type;
|
||||
}
|
||||
|
||||
$type_parts[0] = $namespace_aliases[$type_parts[0]];
|
||||
$type = implode(self::OPERATOR_NAMESPACE, $type_parts);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether the given type represents an array.
|
||||
*
|
||||
* @param string $type A relative or absolute type as defined in the
|
||||
* phpDocumentor documentation.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isTypeAnArray($type)
|
||||
{
|
||||
return substr($type, -2) === self::OPERATOR_ARRAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether the given type represents a PHPDoc keyword.
|
||||
*
|
||||
* @param string $type A relative or absolute type as defined in the
|
||||
* phpDocumentor documentation.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isTypeAKeyword($type)
|
||||
{
|
||||
return in_array(strtolower($type), static::$keywords, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether the given type represents a relative or absolute path.
|
||||
*
|
||||
* This method will detect keywords as being absolute; even though they are
|
||||
* not preceeded by a namespace separator.
|
||||
*
|
||||
* @param string $type A relative or absolute type as defined in the
|
||||
* phpDocumentor documentation.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isRelativeType($type)
|
||||
{
|
||||
return ($type[0] !== self::OPERATOR_NAMESPACE)
|
||||
|| $this->isTypeAKeyword($type);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user