Completed
Push — 1.x ( c183a4...05b51a )
by Alexander
8s
created

CFlowBelowMethodPointcut   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 78
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 22.73%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 9
c 4
b 0
f 0
lcom 1
cbo 2
dl 0
loc 78
ccs 5
cts 22
cp 0.2273
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getKind() 0 4 1
A __construct() 0 8 2
B matches() 0 24 6
1
<?php
2
/*
3
 * Go! AOP framework
4
 *
5
 * @copyright Copyright 2012, 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\Pointcut;
12
13
use ReflectionClass;
14
use Go\Aop\Pointcut;
15
use Go\Aop\PointFilter;
16
use ReflectionMethod;
17
18
/**
19
 * Flow pointcut is a dynamic checker that verifies stack trace to understand is it matches or not
20
 */
21
class CFlowBelowMethodPointcut implements PointFilter, Pointcut
22
{
23
    use PointcutClassFilterTrait;
24
25
    /**
26
     * Filter for the class
27
     *
28
     * @var null|PointFilter
29
     */
30
    protected $internalClassFilter = null;
31
32
    /**
33
     * Filter for the points
34
     *
35
     * @var null|PointFilter
36
     */
37
    protected $internalPointFilter;
38
39
    /**
40
     * Control flow below constructor
41
     *
42
     * @param Pointcut $pointcut Instance of pointcut, that will be used for matching
43
     * @throws \InvalidArgumentException if filter doesn't support methods
44
     */
45 1
    public function __construct(Pointcut $pointcut)
46
    {
47 1
        $this->internalClassFilter = $pointcut->getClassFilter();
48 1
        $this->internalPointFilter = $pointcut;
49 1
        if (!($this->internalPointFilter->getKind() & PointFilter::KIND_METHOD)) {
50
            throw new \InvalidArgumentException("Only method filters are valid for control flow");
51
        }
52 1
    }
53
54
    /**
55
     * Performs matching of point of code
56
     *
57
     * @param mixed $point Specific part of code, can be any Reflection class
58
     * @param null|mixed $context Related context, can be class or namespace
59
     * @param null|string|object $instance Invocation instance or string for static calls
60
     * @param null|array $arguments Dynamic arguments for method
61
     *
62
     * @return bool
63
     */
64
    public function matches($point, $context = null, $instance = null, array $arguments = null)
65
    {
66
        // With single parameter (statically) always matches
67
        if (!$instance) {
68
            return true;
69
        }
70
71
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
72
        foreach ($trace as $stackFrame) {
73
            if (!isset($stackFrame['class'])) {
74
                continue;
75
            }
76
            $refClass = new ReflectionClass($stackFrame['class']);
77
            if (!$this->internalClassFilter->matches($refClass)) {
78
                continue;
79
            }
80
            $refMethod = new ReflectionMethod($stackFrame['class'], $stackFrame['function']);
81
            if ($this->internalPointFilter->matches($refMethod)) {
82
                return true;
83
            }
84
        }
85
86
        return false;
87
    }
88
89
    /**
90
     * Returns the kind of point filter
91
     *
92
     * @return integer
93
     */
94
    public function getKind()
95
    {
96
        return PointFilter::KIND_METHOD | PointFilter::KIND_DYNAMIC;
97
    }
98
}
99