83% of 526OPs |
84% of 92Lines |
72% of 94Branches |
55% of 58Paths |
# | |
---|---|
1 |
<?php |
2 |
|
3 |
namespace mageekguy\atoum\test\adapter; |
4 |
|
5 |
use |
6 |
mageekguy\atoum\exceptions |
7 |
; |
8 |
|
9 |
class invoker implements \arrayAccess, \countable |
10 |
{ |
11 |
protected $function = ''; |
12 |
protected $bindClosureTo = null; |
13 |
protected $currentCall = null; |
14 |
protected $closuresByCall = array(); |
15 |
|
16 |
public function __construct($function)100% |
17 |
{ |
18 |
$this->function = (string) $function; |
19 |
} |
20 |
|
21 |
public function __get($keyword)100% |
22 |
{ |
23 |
return $this->{$keyword}(); |
24 |
} |
25 |
|
26 |
public function __set($keyword, $mixed)100% |
27 |
{ |
28 |
switch ($keyword) |
29 |
{ |
30 |
case 'return': |
31 |
if ($mixed instanceof \closure === false) |
32 |
{ |
33 |
$mixed = function() use ($mixed) { return $mixed; }; |
34 |
} |
35 |
break; |
36 |
|
37 |
case 'throw': |
38 |
if ($mixed instanceof \closure === false) |
39 |
{ |
40 |
$mixed = function() use ($mixed) { throw $mixed; }; |
41 |
} |
42 |
break; |
43 |
|
44 |
default: |
45 |
throw new exceptions\logic\invalidArgument('Keyword \'' . $keyword . '\' is unknown'); |
46 |
} |
47 |
|
48 |
return $this->setClosure($mixed); |
49 |
} |
50 |
|
51 |
public function getFunction()100% |
52 |
{ |
53 |
return $this->function; |
54 |
} |
55 |
|
56 |
public function bindTo($object)80% |
57 |
{ |
58 |
$this->bindClosureTo = $object; |
59 |
|
60 |
foreach ($this->closuresByCall as & $closure) |
61 |
{ |
62 |
$closure = $this->bindClosure($closure); |
63 |
} |
64 |
|
65 |
return $this; |
66 |
} |
67 |
|
68 |
public function count()100% |
69 |
{ |
70 |
return sizeof($this->closuresByCall); |
71 |
} |
72 |
|
73 |
public function doesNothing()100% |
74 |
{ |
75 |
return $this->setClosure(function() {}); |
76 |
} |
77 |
|
78 |
public function doesSomething()100% |
79 |
{ |
80 |
return $this->unsetClosure(); |
81 |
} |
82 |
|
83 |
public function isEmpty()100% |
84 |
{ |
85 |
return (sizeof($this->closuresByCall) <= 0); |
86 |
} |
87 |
|
88 |
public function getCurrentCall()100% |
89 |
{ |
90 |
return $this->currentCall; |
91 |
} |
92 |
|
93 |
public function setClosure(\closure $closure, $call = 0)71% |
94 |
{ |
95 |
if ($this->currentCall !== null) |
96 |
{ |
97 |
$call = $this->currentCall; |
98 |
$this->currentCall = null; |
99 |
} |
100 |
|
101 |
static::checkCall($call); |
102 |
|
103 |
$closure = $this->bindClosure($closure); |
104 |
|
105 |
if ($call === null && sizeof($this->closuresByCall) <= 0) |
106 |
{ |
107 |
$call = 1; |
108 |
} |
109 |
|
110 |
if ($call === null) |
111 |
{ |
112 |
$this->closuresByCall[] = $closure; |
113 |
} |
114 |
else |
115 |
{ |
116 |
$this->closuresByCall[$call] = $closure; |
117 |
} |
118 |
|
119 |
return $this; |
120 |
} |
121 |
|
122 |
public function getClosure($call = 0)100% |
123 |
{ |
124 |
$call = static::checkCall($call); |
125 |
|
126 |
return (isset($this->closuresByCall[$call]) === true ? $this->closuresByCall[$call] : (isset($this->closuresByCall[0]) === false ? null : $this->closuresByCall[0])); |
127 |
} |
128 |
|
129 |
public function closureIsSetForCall($call = 0)100% |
130 |
{ |
131 |
static::checkCall($call); |
132 |
|
133 |
$closureIsSet = (isset($this->closuresByCall[$call]) === true); |
134 |
|
135 |
if ($closureIsSet === false && $call > 0) |
136 |
{ |
137 |
$closureIsSet = (isset($this->closuresByCall[0]) === true); |
138 |
} |
139 |
|
140 |
return $closureIsSet; |
141 |
} |
142 |
|
143 |
public function unsetClosure($call = 0)100% |
144 |
{ |
145 |
if ($this->closureIsSetForCall($call) === false) |
146 |
{ |
147 |
throw new exceptions\logic\invalidArgument('There is no closure defined for call ' . $call); |
148 |
} |
149 |
|
150 |
unset($this->closuresByCall[$call]); |
151 |
|
152 |
return $this; |
153 |
} |
154 |
|
155 |
public function offsetSet($call = null, $mixed = null)100% |
156 |
{ |
157 |
if ($mixed instanceof \closure === false) |
158 |
{ |
159 |
$mixed = function() use ($mixed) { return $mixed; }; |
160 |
} |
161 |
|
162 |
return $this->setClosure($mixed, $call); |
163 |
} |
164 |
|
165 |
public function offsetGet($call)100% |
166 |
{ |
167 |
return $this->atCall($call); |
168 |
} |
169 |
|
170 |
public function offsetUnset($call)100% |
171 |
{ |
172 |
return $this->unsetClosure($call); |
173 |
} |
174 |
|
175 |
public function offsetExists($call)100% |
176 |
{ |
177 |
return $this->closureIsSetForCall($call) ?: $this->closureIsSetForCall(0); |
178 |
} |
179 |
|
180 |
public function atCall($call)100% |
181 |
{ |
182 |
$this->currentCall = self::checkCall($call); |
183 |
|
184 |
return $this; |
185 |
} |
186 |
|
187 |
public function invoke(array $arguments = array(), $call = 0)100% |
188 |
{ |
189 |
if ($this->closureIsSetForCall($call) === false) |
190 |
{ |
191 |
throw new exceptions\logic\invalidArgument('There is no closure defined for call ' . $call); |
192 |
} |
193 |
|
194 |
return call_user_func_array($this->getClosure($call), $arguments); |
195 |
} |
196 |
|
197 |
protected function bindClosure(\closure $closure)60% |
198 |
{ |
199 |
if ($this->bindClosureTo !== null && static::isBindable($closure) === true) |
200 |
{ |
201 |
$closure = $closure->bindTo($this->bindClosureTo); |
202 |
} |
203 |
|
204 |
return $closure; |
205 |
} |
206 |
|
207 |
protected static function checkCall($call)100% |
208 |
{ |
209 |
$call = (int) $call; |
210 |
|
211 |
if ($call < 0) |
212 |
{ |
213 |
throw new exceptions\logic\invalidArgument('Call number must be greater than or equal to zero'); |
214 |
} |
215 |
|
216 |
return $call; |
217 |
} |
218 |
|
219 |
protected static function isBindable(\closure $closure)0% |
220 |
{ |
221 |
$isBindable = (version_compare(PHP_VERSION, '5.4.0') >= 0); |
222 |
|
223 |
if ($isBindable === true) |
224 |
{ |
225 |
$reflectedClosure = new \reflectionFunction($closure); |
226 |
|
227 |
$isBindable = ($reflectedClosure->getClosureThis() !== null || $reflectedClosure->getClosureScopeClass() === null); |
228 |
} |
229 |
|
230 |
return $isBindable; |
231 |
} |
232 |
} |