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

DynamicClosureMethodInvocation::__invoke()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
ccs 13
cts 13
cp 1
rs 8.9713
cc 3
eloc 14
nc 4
nop 2
crap 3
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