Completed
Pull Request — master (#253)
by Alexander
02:59
created

DynamicClosureMethodInvocation   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 85%

Importance

Changes 4
Bugs 1 Features 1
Metric Value
wmc 14
c 4
b 1
f 1
lcom 1
cbo 1
dl 0
loc 101
ccs 34
cts 40
cp 0.85
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
D proceed() 0 41 10
B __invoke() 0 28 4
1
<?php
2
/*
3
 * Go! AOP framework
4
 *
5
 * @copyright Copyright 2015, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\Aop\Framework;
12
13
class DynamicClosureMethodInvocation extends AbstractMethodInvocation
14
{
15
    /**
16
     * Closure to use
17
     *
18
     * @var \Closure
19
     */
20
    protected $closureToCall = null;
21
22
    /**
23
     * Previous instance/scope of invocation
24
     *
25
     * @var null|object|string
26
     */
27
    protected $previousInstance = null;
28
29
    /**
30
     * Invokes original method and return result from it
31
     *
32
     * @return mixed
33
     */
34 7
    public function proceed()
35
    {
36 7
        if (isset($this->advices[$this->current])) {
37
            /** @var $currentInterceptor \Go\Aop\Intercept\Interceptor */
38 1
            $currentInterceptor = $this->advices[$this->current++];
39
40 1
            return $currentInterceptor->invoke($this);
41
        }
42
43
        // Fill the closure only once if it's empty
44 7
        if (!$this->closureToCall) {
45 7
            $this->closureToCall = $this->reflectionMethod->getClosure($this->instance);
46
        }
47
48
        // Rebind the closure if instance was changed since last time
49 7
        if ($this->previousInstance !== $this->instance) {
50 7
            $this->closureToCall    = $this->closureToCall->bindTo($this->instance, $this->reflectionMethod->class);
51 7
            $this->previousInstance = $this->instance;
52
        }
53
54 7
        $closureToCall = $this->closureToCall;
55 7
        $args          = $this->arguments;
56
57 7
        switch (count($args)) {
58
            case 0:
59 3
                return $closureToCall();
60
            case 1:
61 3
                return $closureToCall($args[0]);
62
            case 2:
63 3
                return $closureToCall($args[0], $args[1]);
64
            case 3:
65 2
                return $closureToCall($args[0], $args[1], $args[2]);
66
            case 4:
67 2
                return $closureToCall($args[0], $args[1], $args[2], $args[3]);
68 2
            case 5:
69 2
                return $closureToCall($args[0], $args[1], $args[2], $args[3], $args[4]);
70
            default:
71 2
                return forward_static_call_array($closureToCall, $args);
72
        }
73
74
    }
75
76
    /**
77
     * Invokes current method invocation with all interceptors
78
     *
79
     * @param null|object|string $instance Invocation instance (class name for static methods)
80
     * @param array $arguments List of arguments for method invocation
81
     * @param array $variadicArguments Additional list of variadic arguments
82
     *
83
     * @return mixed Result of invocation
84
     */
85 27
    final public function __invoke($instance = null, array $arguments = [], array $variadicArguments = [])
86
    {
87 27
        if ($this->level) {
88 3
            $this->stackFrames[] = [$this->arguments, $this->instance, $this->current];
89
        }
90
91 27
        if (!empty($variadicArguments)) {
92
            $arguments = array_merge($arguments, $variadicArguments);
93
        }
94
95
        try {
96 27
            ++$this->level;
97
98 27
            $this->current   = 0;
99 27
            $this->instance  = $instance;
100 27
            $this->arguments = $arguments;
101
102 27
            $result = $this->proceed();
103 27
        } finally {
104 27
            --$this->level;
105
        }
106
107 27
        if ($this->level) {
108 3
            list($this->arguments, $this->instance, $this->current) = array_pop($this->stackFrames);
109
        }
110
111 27
        return $result;
112
    }
113
}
114