Completed
Push — 1.x ( ebfb64...c183a4 )
by Alexander
20s
created

ClassFieldAccess::getValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 0
cts 5
cp 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
crap 2
1
<?php
2
/*
3
 * Go! AOP framework
4
 *
5
 * @copyright Copyright 2011, 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
use Go\Aop\AspectException;
14
use Go\Aop\Intercept\FieldAccess;
15
use Go\Aop\Intercept\Interceptor;
16
use ReflectionProperty;
17
18
/**
19
 * Represents a field access joinpoint
20
 */
21
class ClassFieldAccess extends AbstractJoinpoint implements FieldAccess
22
{
23
24
    /**
25
     * Instance of object for accessing
26
     *
27
     * @var object
28
     */
29
    protected $instance = null;
30
31
    /**
32
     * Instance of reflection property
33
     *
34
     * @var ReflectionProperty
35
     */
36
    protected $reflectionProperty;
37
38
    /**
39
     * New value to set
40
     *
41
     * @var mixed
42
     */
43
    protected $newValue = null;
44
45
    /**
46
     * Access type for field access
47
     *
48
     * @var integer
49
     */
50
    private $accessType;
51
52
    /**
53
     * Copy of the original value of property
54
     *
55
     * @var mixed
56
     */
57
    private $value = null;
58
59
    /**
60
     * Constructor for field access
61
     *
62
     * @param string $className Class name
63
     * @param string $fieldName Field name
64
     * @param $advices array List of advices for this invocation
65
     */
66
    public function __construct($className, $fieldName, array $advices)
67
    {
68
        parent::__construct($advices);
69
70
        $this->reflectionProperty = $reflectionProperty = new ReflectionProperty($className, $fieldName);
71
        // Give an access to protected field
72
        if ($reflectionProperty->isProtected()) {
73
            $reflectionProperty->setAccessible(true);
74
        }
75
    }
76
77
    /**
78
     * Returns the access type.
79
     *
80
     * @return integer
81
     */
82
    public function getAccessType()
83
    {
84
        return $this->accessType;
85
    }
86
87
    /**
88
     * Gets the field being accessed.
89
     *
90
     * @return ReflectionProperty the field being accessed.
91
     */
92
    public function getField()
93
    {
94
        return $this->reflectionProperty;
95
    }
96
97
    /**
98
     * Gets the current value of property
99
     *
100
     * @return mixed
101
     */
102
    public function &getValue()
103
    {
104
        $value = &$this->value;
105
106
        return $value;
107
    }
108
109
    /**
110
     * Gets the value that must be set to the field.
111
     *
112
     * @return mixed
113
     */
114
    public function &getValueToSet()
115
    {
116
        $newValue = &$this->newValue;
117
118
        return $newValue;
119
    }
120
121
    /**
122
     * Checks scope rules for accessing property
123
     *
124
     * @param int $stackLevel Stack level for check
125
     *
126
     * @return true if access is OK
127
     */
128
    public function ensureScopeRule($stackLevel = 2)
129
    {
130
        $property = $this->reflectionProperty;
131
132
        if ($property->isProtected()) {
133
            $backTrace     = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $stackLevel+1);
134
            $accessor      = isset($backTrace[$stackLevel]) ? $backTrace[$stackLevel] : [];
135
            $propertyClass = $property->class;
136
            if (isset($accessor['class'])) {
137
                if ($accessor['class'] === $propertyClass || is_subclass_of($accessor['class'], $propertyClass)) {
1 ignored issue
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $propertyClass can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
138
                    return true;
139
                }
140
            }
141
            throw new AspectException("Cannot access protected property {$propertyClass}::{$property->name}");
142
        }
143
144
        return true;
145
    }
146
147
    /**
148
     * Proceed to the next interceptor in the Chain
149
     *
150
     * Typically this method is called inside previous closure, as instance of Joinpoint is passed to callback
151
     * Do not call this method directly, only inside callback closures.
152
     *
153
     * @return void For field interceptor there is no return values
154
     */
155
    final public function proceed()
156
    {
157
        if (isset($this->advices[$this->current])) {
158
            /** @var $currentInterceptor Interceptor */
159
            $currentInterceptor = $this->advices[$this->current++];
160
161
            $currentInterceptor->invoke($this);
162
        }
163
    }
164
165
    /**
166
     * Invokes current field access with all interceptors
167
     *
168
     * @param object $instance Instance of object
169
     * @param integer $accessType Type of access: READ or WRITE
170
     * @param mixed $originalValue Original value of property
171
     * @param mixed $newValue New value to set
172
     *
173
     * @return mixed
174
     */
175
    final public function &__invoke($instance, $accessType, &$originalValue, $newValue = NAN)
176
    {
177
        if ($this->level) {
178
            array_push($this->stackFrames, [$this->instance, $this->accessType, &$this->value, &$this->newValue]);
179
        }
180
181
        ++$this->level;
182
183
        $this->current    = 0;
184
        $this->instance   = $instance;
185
        $this->accessType = $accessType;
186
        $this->value      = &$originalValue;
187
        $this->newValue   = $newValue;
188
189
        $this->proceed();
190
191
        --$this->level;
192
193
        if ($this->level) {
194
            list($this->instance, $this->accessType, $this->value, $this->newValue) = array_pop($this->stackFrames);
195
        }
196
197
        if ($accessType == self::READ) {
198
            $result = &$this->value;
199
        } else {
200
            $result = &$this->newValue;
201
        };
202
203
        return $result;
204
205
    }
206
207
    /**
208
     * Returns the object that holds the current joinpoint's static
209
     * part.
210
     *
211
     * @return object|null the object (can be null if the accessible object is
212
     * static).
213
     */
214
    final public function getThis()
215
    {
216
        return $this->instance;
217
    }
218
219
    /**
220
     * Returns the static part of this joinpoint.
221
     *
222
     * @return object
223
     */
224
    final public function getStaticPart()
225
    {
226
        return $this->getField();
227
    }
228
229
    /**
230
     * Returns a friendly description of current joinpoint
231
     *
232
     * @return string
233
     */
234
    final public function __toString()
235
    {
236
        return sprintf(
237
            "%s(%s%s%s)",
238
            $this->accessType == self::READ ? 'get' : 'set',
239
            is_object($this->instance) ? get_class($this->instance) : $this->instance,
240
            $this->reflectionProperty->isStatic() ? '::' : '->',
241
            $this->reflectionProperty->name
242
        );
243
    }
244
}
245