Completed
Push — 1.x ( e42f79...4120cd )
by Alexander
02:50
created

DynamicClosureMethodInvocation::proceed()   D

Complexity

Conditions 10
Paths 29

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 10.7998

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 41
ccs 20
cts 25
cp 0.8
rs 4.8196
cc 10
eloc 26
nc 29
nop 0
crap 10.7998

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 scope of invocation
24
     *
25
     * @var null
26
     */
27
    protected $previousInstance = null;
28
29
    /**
30
     * Invokes original method and return result from it
31
     *
32
     * @return mixed
33
     */
34 6
    public function proceed()
35
    {
36 6
        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 6
        if (!$this->closureToCall) {
45 6
            $this->closureToCall = $this->reflectionMethod->getClosure($this->instance);
46
        }
47
48
        // Rebind the closure if instance was changed since last time
49 6
        if ($this->previousInstance !== $this->instance) {
50 6
            $this->closureToCall    = $this->closureToCall->bindTo($this->instance, $this->reflectionMethod->class);
51 6
            $this->previousInstance = $this->instance;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->instance of type object is incompatible with the declared type null of property $previousInstance.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
52
        }
53
54 6
        $closureToCall = $this->closureToCall;
55 6
        $args          = $this->arguments;
56
57 6
        switch (count($args)) {
58
            case 0:
59 3
                return $closureToCall();
60
            case 1:
61 2
                return $closureToCall($args[0]);
62
            case 2:
63 2
                return $closureToCall($args[0], $args[1]);
64
            case 3:
65 1
                return $closureToCall($args[0], $args[1], $args[2]);
66
            case 4:
67 1
                return $closureToCall($args[0], $args[1], $args[2], $args[3]);
68 1
            case 5:
69 1
                return $closureToCall($args[0], $args[1], $args[2], $args[3], $args[4]);
70
            default:
71 1
                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
     *
82
     * @return mixed Result of invocation
83
     */
84 24
    final public function __invoke($instance = null, array $arguments = [])
85
    {
86 24
        if ($this->level) {
87 3
            $this->stackFrames[] = [$this->arguments, $this->instance, $this->current];
88
        }
89
90
        try {
91 24
            ++$this->level;
92
93 24
            $this->current   = 0;
94 24
            $this->instance  = $instance;
0 ignored issues
show
Documentation Bug introduced by
It seems like $instance can also be of type string. However, the property $instance is declared as type object. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
95 24
            $this->arguments = $arguments;
96
97 24
            $result = $this->proceed();
98 24
        } finally {
99 24
            --$this->level;
100
        }
101
102 24
        if ($this->level) {
103 3
            list($this->arguments, $this->instance, $this->current) = array_pop($this->stackFrames);
104
        }
105
106 24
        return $result;
107
    }
108
}
109