Completed
Push — master ( c5668e...1fa99d )
by Ryosuke
03:35
created

CoOption::validateOptions()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 14
ccs 10
cts 10
cp 1
rs 8.8571
cc 5
eloc 9
nc 4
nop 1
crap 5
1
<?php
2
3
namespace mpyw\Co\Internal;
4
5
class CoOption implements \ArrayAccess
6
{
7
    /**
8
     * Field types.
9
     * @var array
10
     */
11
    private static $types = [
12
        'throw' => 'Bool', // Throw CURLExceptions?
13
        'pipeline' => 'Bool', // Use HTTP/1.1 pipelining?
14
        'multiplex' => 'Bool', // Use HTTP/2 multiplexing?
15
        'autoschedule' => 'Bool', // Use AutoScheduler?
16
        'interval' => 'NaturalFloat', // curl_multi_select() timeout
17
        'concurrency' => 'NaturalInt', // Limit of TCP connections
18
    ];
19
20
    /**
21
     * Default values.
22
     * @var array
23
     */
24
    private static $defaults = [
25
        'throw' => true,
26
        'pipeline' => false,
27
        'multiplex' => true,
28
        'autoschedule' => false,
29
        'interval' => 0.002,
30
        'concurrency' => 6,
31
    ];
32
33
    /**
34
     * Actual values.
35
     * @var array
36
     */
37
    private $options;
38
39
    /**
40
     * Set default options.
41
     * @param array $options
42
     */
43 8
    public static function setDefault(array $options)
44 8
    {
45 8
        self::$defaults = self::validateOptions($options) + self::$defaults;
46 8
    }
47
48
    /**
49
     * Get default options.
50
     * @return array $options
51
     */
52 8
    public static function getDefault()
53 8
    {
54 8
        return self::$defaults;
55
    }
56
57
    /**
58
     * Constructor.
59
     * @param array $options
60
     */
61 44
    public function __construct(array $options = [])
62 44
    {
63 44
        $this->options = self::validateOptions($options) + self::$defaults;
64 43
    }
65
66
    /**
67
     * Reconfigure to get new instance.
68
     * @return CoOption
69
     */
70 1
    public function reconfigure(array $options)
71 1
    {
72 1
        return new self($options + $this->options);
73
    }
74
75
    /**
76
     * Implemention of ArrayAccess.
77
     * @param  mixed $offset
78
     * @return bool
79
     */
80 1
    public function offsetExists($offset)
81 1
    {
82 1
        return isset($this->options[$offset]);
83
    }
84
85
    /**
86
     * Implemention of ArrayAccess.
87
     * @param  mixed $offset
88
     * @return mixed
89
     */
90 41
    public function offsetGet($offset)
91 41
    {
92 41
        if (!isset($this->options[$offset])) {
93 1
            throw new \DomainException('Undefined field: ' + $offset);
94
        }
95 40
        return $this->options[$offset];
96
    }
97
98
    /**
99
     * Implemention of ArrayAccess.
100
     * @param  mixed $offset
101
     * @param  mixed $value
102
     * @throws BadMethodCallException
103
     */
104 1
    public function offsetSet($offset, $value)
105 1
    {
106 1
        throw new \BadMethodCallException('The instance of CoOptions is immutable.');
107
    }
108
109
    /**
110
     * Implemention of ArrayAccess.
111
     * @param  mixed $offset
112
     * @throws BadMethodCallException
113
     */
114 1
    public function offsetUnset($offset)
115 1
    {
116 1
        throw new \BadMethodCallException('The instance of CoOptions is immutable.');
117
    }
118
119
    /**
120
     * Validate options.
121
     * @param  array $options
122
     * @return array
123
     */
124 49
    private static function validateOptions(array $options)
125 49
    {
126 49
        foreach ($options as $key => $value) {
127 25
            if (!isset(self::$types[$key])) {
128 1
                throw new \DomainException("Unknown option: $key");
129
            }
130 25
            if ($key === 'autoschedule' && !defined('CURLMOPT_MAX_TOTAL_CONNECTIONS')) {
131 1
                throw new \OutOfBoundsException('"autoschedule" can be used only on PHP 7.0.7 or later.');
132
            }
133 24
            $validator = [__CLASS__, 'validate' . self::$types[$key]];
134 24
            $options[$key] = $validator($key, $value);
135
        }
136 48
        return $options;
137
    }
138
139
    /**
140
     * Validate bool value.
141
     * @param  string $key
142
     * @param  mixed  $value
143
     * @throws InvalidArgumentException
144
     * @return bool
145
     */
146 16
    private static function validateBool($key, $value)
147 16
    {
148 16
        $value = filter_var($value, FILTER_VALIDATE_BOOLEAN, [
149 16
            'flags' => FILTER_NULL_ON_FAILURE,
150
        ]);
151 16
        if ($value === null) {
152 1
            throw new \InvalidArgumentException("Option[$key] must be boolean.");
153
        }
154 16
        return $value;
155
    }
156
157
    /**
158
     * Validate natural float value.
159
     * @param  string $key
160
     * @param  mixed  $value
161
     * @throws InvalidArgumentException
162
     * @return float
163
     */
164 7 View Code Duplication
    private static function validateNaturalFloat($key, $value)
165 7
    {
166 7
        $value = filter_var($value, FILTER_VALIDATE_FLOAT);
167 7
        if ($value === false) {
168 1
            throw new \InvalidArgumentException("Option[$key] must be float.");
169
        }
170 7
        if ($value < 0.0) {
171 1
            throw new \DomainException("Option[$key] must be positive or zero.");
172
        }
173 7
        return $value;
174
    }
175
176
    /**
177
     * Validate natural int value.
178
     * @param  string $key
179
     * @param  mixed  $value
180
     * @throws InvalidArgumentException
181
     * @return int
182
     */
183 17 View Code Duplication
    private static function validateNaturalInt($key, $value)
184 17
    {
185 17
        $value = filter_var($value, FILTER_VALIDATE_INT);
186 17
        if ($value === false) {
187 1
            throw new \InvalidArgumentException("Option[$key] must be integer.");
188
        }
189 17
        if ($value < 0) {
190 1
            throw new \DomainException("Option[$key] must be positive or zero.");
191
        }
192 17
        return $value;
193
    }
194
}
195