1<?php
2/*
3 * This file is part of PHPUnit.
4 *
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11/**
12 * Constraint that asserts that the value it is evaluated for is of a
13 * specified type.
14 *
15 * The expected value is passed in the constructor.
16 */
17class PHPUnit_Framework_Constraint_IsType extends PHPUnit_Framework_Constraint
18{
19    const TYPE_ARRAY    = 'array';
20    const TYPE_BOOL     = 'bool';
21    const TYPE_FLOAT    = 'float';
22    const TYPE_INT      = 'int';
23    const TYPE_NULL     = 'null';
24    const TYPE_NUMERIC  = 'numeric';
25    const TYPE_OBJECT   = 'object';
26    const TYPE_RESOURCE = 'resource';
27    const TYPE_STRING   = 'string';
28    const TYPE_SCALAR   = 'scalar';
29    const TYPE_CALLABLE = 'callable';
30
31    /**
32     * @var array
33     */
34    protected $types = [
35        'array'    => true,
36        'boolean'  => true,
37        'bool'     => true,
38        'double'   => true,
39        'float'    => true,
40        'integer'  => true,
41        'int'      => true,
42        'null'     => true,
43        'numeric'  => true,
44        'object'   => true,
45        'real'     => true,
46        'resource' => true,
47        'string'   => true,
48        'scalar'   => true,
49        'callable' => true
50    ];
51
52    /**
53     * @var string
54     */
55    protected $type;
56
57    /**
58     * @param string $type
59     *
60     * @throws PHPUnit_Framework_Exception
61     */
62    public function __construct($type)
63    {
64        parent::__construct();
65
66        if (!isset($this->types[$type])) {
67            throw new PHPUnit_Framework_Exception(
68                sprintf(
69                    'Type specified for PHPUnit_Framework_Constraint_IsType <%s> ' .
70                    'is not a valid type.',
71                    $type
72                )
73            );
74        }
75
76        $this->type = $type;
77    }
78
79    /**
80     * Evaluates the constraint for parameter $other. Returns true if the
81     * constraint is met, false otherwise.
82     *
83     * @param mixed $other Value or object to evaluate.
84     *
85     * @return bool
86     */
87    protected function matches($other)
88    {
89        switch ($this->type) {
90            case 'numeric':
91                return is_numeric($other);
92
93            case 'integer':
94            case 'int':
95                return is_int($other);
96
97            case 'double':
98            case 'float':
99            case 'real':
100                return is_float($other);
101
102            case 'string':
103                return is_string($other);
104
105            case 'boolean':
106            case 'bool':
107                return is_bool($other);
108
109            case 'null':
110                return is_null($other);
111
112            case 'array':
113                return is_array($other);
114
115            case 'object':
116                return is_object($other);
117
118            case 'resource':
119                return is_resource($other) || is_string(@get_resource_type($other));
120
121            case 'scalar':
122                return is_scalar($other);
123
124            case 'callable':
125                return is_callable($other);
126        }
127    }
128
129    /**
130     * Returns a string representation of the constraint.
131     *
132     * @return string
133     */
134    public function toString()
135    {
136        return sprintf(
137            'is of type "%s"',
138            $this->type
139        );
140    }
141}
142