Skip to content

Commit ca2c470

Browse files
committed
Added more explicit exceptions
1 parent 64499ca commit ca2c470

8 files changed

+94
-43
lines changed

Diff for: src/Exception/InvocationException.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Invoker\Exception;
4+
5+
/**
6+
* Impossible to invoke the callable.
7+
*
8+
* @author Matthieu Napoli <[email protected]>
9+
*/
10+
class InvocationException extends \Exception
11+
{
12+
}

Diff for: src/Exception/NotCallableException.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Invoker\Exception;
4+
5+
/**
6+
* The given callable is not actually callable.
7+
*
8+
* @author Matthieu Napoli <[email protected]>
9+
*/
10+
class NotCallableException extends InvocationException
11+
{
12+
}

Diff for: src/Exception/NotEnoughParametersException.php

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Invoker\Exception;
4+
5+
/**
6+
* Not enough parameters could be resolved to invoke the callable.
7+
*
8+
* @author Matthieu Napoli <[email protected]>
9+
*/
10+
class NotEnoughParametersException extends InvocationException
11+
{
12+
}

Diff for: src/Invoker.php

+35-11
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
namespace Invoker;
44

55
use Interop\Container\ContainerInterface;
6+
use Invoker\Exception\NotCallableException;
7+
use Invoker\Exception\NotEnoughParametersException;
68
use Invoker\ParameterResolver\AssociativeArrayResolver;
79
use Invoker\ParameterResolver\DefaultValueResolver;
810
use Invoker\ParameterResolver\NumericArrayResolver;
911
use Invoker\ParameterResolver\ParameterResolver;
1012
use Invoker\ParameterResolver\ResolverChain;
1113
use Invoker\Reflection\CallableReflection;
14+
use ReflectionFunctionAbstract;
1215

1316
/**
1417
* Invoke a callable.
@@ -34,12 +37,7 @@ public function __construct(ParameterResolver $parameterResolver = null, Contain
3437
}
3538

3639
/**
37-
* Call the given function using the given parameters.
38-
*
39-
* @param callable|string|array $callable Function to call.
40-
* @param array $parameters Parameters to use.
41-
*
42-
* @return mixed Result of the function.
40+
* {@inheritdoc}
4341
*/
4442
public function call($callable, array $parameters = array())
4543
{
@@ -52,6 +50,8 @@ public function call($callable, array $parameters = array())
5250

5351
$args = $this->parameterResolver->getParameters($callableReflection, $parameters, array());
5452

53+
$this->assertMandatoryParametersAreResolved($args, $callableReflection);
54+
5555
// Sort by array key because invokeArgs ignores numeric keys
5656
ksort($args);
5757

@@ -107,6 +107,7 @@ public function getContainer()
107107
/**
108108
* @param callable|string|array $callable
109109
* @return callable
110+
* @throws NotCallableException
110111
*/
111112
private function resolveCallableFromContainer($callable)
112113
{
@@ -125,7 +126,7 @@ private function resolveCallableFromContainer($callable)
125126
if ($this->container->has($callable)) {
126127
return $this->container->get($callable);
127128
} else {
128-
throw new \RuntimeException(sprintf(
129+
throw new NotCallableException(sprintf(
129130
'%s is neither a callable or a valid container entry',
130131
$callable
131132
));
@@ -139,15 +140,15 @@ private function resolveCallableFromContainer($callable)
139140
$callable[0] = $this->container->get($callable[0]);
140141
return $callable;
141142
} elseif ($isStaticCallToNonStaticMethod) {
142-
throw new \RuntimeException(sprintf(
143+
throw new NotCallableException(sprintf(
143144
'Cannot call %s::%s() because %s() is not a static method and "%s" is not a container entry',
144145
$callable[0],
145146
$callable[1],
146147
$callable[1],
147148
$callable[0]
148149
));
149150
} else {
150-
throw new \RuntimeException(sprintf(
151+
throw new NotCallableException(sprintf(
151152
'Cannot call %s on %s because it is not a class nor a valid container entry',
152153
$callable[1],
153154
$callable[0]
@@ -159,10 +160,14 @@ private function resolveCallableFromContainer($callable)
159160
return $callable;
160161
}
161162

163+
/**
164+
* @param callable $callable
165+
* @throws NotCallableException
166+
*/
162167
private function assertIsCallable($callable)
163168
{
164169
if (! is_callable($callable)) {
165-
throw new \RuntimeException(sprintf(
170+
throw new NotCallableException(sprintf(
166171
'%s is not a callable',
167172
is_object($callable) ? 'Instance of ' . get_class($callable) : var_export($callable, true)
168173
));
@@ -181,9 +186,28 @@ private function isStaticCallToNonStaticMethod($callable)
181186
list($class, $method) = $callable;
182187
$reflection = new \ReflectionMethod($class, $method);
183188

184-
return !$reflection->isStatic();
189+
return ! $reflection->isStatic();
185190
}
186191

187192
return false;
188193
}
194+
195+
private function assertMandatoryParametersAreResolved($parameters, ReflectionFunctionAbstract $reflection)
196+
{
197+
$parameterCount = $reflection->getNumberOfRequiredParameters();
198+
199+
// TODO is there a more efficient way?
200+
for ($i = 0; $i < $parameterCount; $i++) {
201+
if (! array_key_exists($i, $parameters)) {
202+
$reflectionParameters = $reflection->getParameters();
203+
$parameter = $reflectionParameters[$i];
204+
205+
throw new NotEnoughParametersException(sprintf(
206+
'Unable to invoke the callable because no value was given for parameter %d ($%s)',
207+
$i + 1,
208+
$parameter->name
209+
));
210+
}
211+
}
212+
}
189213
}

Diff for: src/InvokerInterface.php

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
namespace Invoker;
44

5+
use Invoker\Exception\InvocationException;
6+
use Invoker\Exception\NotCallableException;
7+
use Invoker\Exception\NotEnoughParametersException;
8+
59
/**
610
* Invoke a callable.
711
*
@@ -16,6 +20,10 @@ interface InvokerInterface
1620
* @param array $parameters Parameters to use.
1721
*
1822
* @return mixed Result of the function.
23+
*
24+
* @throws InvocationException Base exception class for all the sub-exceptions below.
25+
* @throws NotCallableException
26+
* @throws NotEnoughParametersException
1927
*/
2028
public function call($callable, array $parameters = array());
2129
}

Diff for: src/ParameterResolver/ResolverChain.php

-24
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ public function getParameters(
2828
array $providedParameters,
2929
array $resolvedParameters
3030
) {
31-
$parameterCount = $reflection->getNumberOfRequiredParameters();
32-
3331
foreach ($this->resolvers as $resolver) {
3432
// TODO optimize: stop traversing once all parameters are resolved
3533
$resolvedParameters = $resolver->getParameters(
@@ -39,8 +37,6 @@ public function getParameters(
3937
);
4038
}
4139

42-
$this->assertMandatoryParametersAreResolved($parameterCount, $resolvedParameters, $reflection);
43-
4440
return $resolvedParameters;
4541
}
4642

@@ -63,24 +59,4 @@ public function prependResolver(ParameterResolver $resolver)
6359
{
6460
array_unshift($this->resolvers, $resolver);
6561
}
66-
67-
private function assertMandatoryParametersAreResolved(
68-
$parameterCount,
69-
$parameters,
70-
ReflectionFunctionAbstract $reflection
71-
) {
72-
// TODO is there a more efficient way?
73-
for ($i = 0; $i < $parameterCount; $i++) {
74-
if (! array_key_exists($i, $parameters)) {
75-
$reflectionParameters = $reflection->getParameters();
76-
$parameter = $reflectionParameters[$i];
77-
78-
throw new \RuntimeException(sprintf(
79-
'Unable to invoke the callable because no value was given for parameter %d ($%s)',
80-
$i + 1,
81-
$parameter->name
82-
));
83-
}
84-
}
85-
}
8662
}

Diff for: src/Reflection/CallableReflection.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Invoker\Reflection;
44

5+
use Invoker\Exception\NotCallableException;
6+
57
/**
68
* Create a reflection object from a callable.
79
*
@@ -14,6 +16,8 @@ class CallableReflection
1416
*
1517
* @return \ReflectionFunctionAbstract
1618
*
19+
* @throws NotCallableException
20+
*
1721
* TODO Use the `callable` type-hint once support for PHP 5.4 and up.
1822
*/
1923
public static function create($callable)
@@ -45,7 +49,7 @@ public static function create($callable)
4549
return new \ReflectionFunction($callable);
4650
}
4751

48-
throw new \RuntimeException(sprintf(
52+
throw new NotCallableException(sprintf(
4953
'%s is not a callable',
5054
is_string($callable) ? $callable : 'Instance of ' . get_class($callable)
5155
));

Diff for: tests/InvokerTest.php

+10-7
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,15 @@ public function should_return_the_callable_return_value()
7474

7575
/**
7676
* @test
77-
* @expectedException \RuntimeException
78-
* @expectedExceptionMessage Unable to invoke the callable because no value was given for parameter 1 ($foo)
77+
* @expectedException \Invoker\Exception\NotEnoughParametersException
78+
* @expectedExceptionMessage Unable to invoke the callable because no value was given for parameter 2 ($bar)
7979
*/
8080
public function should_throw_if_no_value_for_parameter()
8181
{
82-
$this->invoker->call(function ($foo) {});
82+
$this->invoker->call(function ($foo, $bar, $baz) {}, array(
83+
'foo' => 'foo',
84+
'baz' => 'baz',
85+
));
8386
}
8487

8588
/**
@@ -207,7 +210,7 @@ public function should_resolve_array_callable_from_container_with_class_name()
207210

208211
/**
209212
* @test
210-
* @expectedException \RuntimeException
213+
* @expectedException \Invoker\Exception\NotCallableException
211214
* @expectedExceptionMessage Cannot call Invoker\Test\InvokerTestFixture::foo() because foo() is not a static method and "Invoker\Test\InvokerTestFixture" is not a container entry
212215
*/
213216
public function should_not_invoke_statically_a_non_static_method()
@@ -217,7 +220,7 @@ public function should_not_invoke_statically_a_non_static_method()
217220

218221
/**
219222
* @test
220-
* @expectedException \RuntimeException
223+
* @expectedException \Invoker\Exception\NotCallableException
221224
* @expectedExceptionMessage 'foo' is not a callable
222225
*/
223226
public function should_throw_if_calling_non_callable_without_container()
@@ -228,7 +231,7 @@ public function should_throw_if_calling_non_callable_without_container()
228231

229232
/**
230233
* @test
231-
* @expectedException \RuntimeException
234+
* @expectedException \Invoker\Exception\NotCallableException
232235
* @expectedExceptionMessage foo is neither a callable or a valid container entry
233236
*/
234237
public function should_throw_if_calling_non_callable_with_container()
@@ -239,7 +242,7 @@ public function should_throw_if_calling_non_callable_with_container()
239242

240243
/**
241244
* @test
242-
* @expectedException \RuntimeException
245+
* @expectedException \Invoker\Exception\NotCallableException
243246
* @expectedExceptionMessage Instance of stdClass is not a callable
244247
*/
245248
public function should_throw_if_calling_non_callable_object()

0 commit comments

Comments
 (0)