1<?php
2/**
3 * This file is part of phpDocumentor.
4 *
5 * For the full copyright and license information, please view the LICENSE
6 * file that was distributed with this source code.
7 *
8 * @copyright 2010-2015 Mike van Riel<mike@phpdoc.org>
9 * @license   http://www.opensource.org/licenses/mit-license.php MIT
10 * @link      http://phpdoc.org
11 */
12
13namespace phpDocumentor\Reflection\Types;
14
15use ArrayIterator;
16use IteratorAggregate;
17use phpDocumentor\Reflection\Type;
18
19/**
20 * Value Object representing a Compound Type.
21 *
22 * A Compound Type is not so much a special keyword or object reference but is a series of Types that are separated
23 * using an OR operator (`|`). This combination of types signifies that whatever is associated with this compound type
24 * may contain a value with any of the given types.
25 */
26final class Compound implements Type, IteratorAggregate
27{
28    /** @var Type[] */
29    private $types;
30
31    /**
32     * Initializes a compound type (i.e. `string|int`) and tests if the provided types all implement the Type interface.
33     *
34     * @param Type[] $types
35     * @throws \InvalidArgumentException when types are not all instance of Type
36     */
37    public function __construct(array $types)
38    {
39        foreach ($types as $type) {
40            if (!$type instanceof Type) {
41                throw new \InvalidArgumentException('A compound type can only have other types as elements');
42            }
43        }
44
45        $this->types = $types;
46    }
47
48    /**
49     * Returns the type at the given index.
50     *
51     * @param integer $index
52     *
53     * @return Type|null
54     */
55    public function get($index)
56    {
57        if (!$this->has($index)) {
58            return null;
59        }
60
61        return $this->types[$index];
62    }
63
64    /**
65     * Tests if this compound type has a type with the given index.
66     *
67     * @param integer $index
68     *
69     * @return bool
70     */
71    public function has($index)
72    {
73        return isset($this->types[$index]);
74    }
75
76    /**
77     * Returns a rendered output of the Type as it would be used in a DocBlock.
78     *
79     * @return string
80     */
81    public function __toString()
82    {
83        return implode('|', $this->types);
84    }
85
86    /**
87     * {@inheritdoc}
88     */
89    public function getIterator()
90    {
91        return new ArrayIterator($this->types);
92    }
93}
94