1 | <?php |
||||
2 | namespace Elgg; |
||||
3 | /** |
||||
4 | * Wrap an object and display warnings whenever the object's variables are |
||||
5 | * accessed or a method is used. It can also be used to wrap a string. |
||||
6 | * |
||||
7 | * Note that the wrapper will not share the type of the wrapped object and will |
||||
8 | * fail type hints, instanceof, etc. |
||||
9 | * |
||||
10 | * This was introduced for deprecating passing particular variables to views |
||||
11 | * automatically in elgg_view(). |
||||
12 | * It can be removed once that use is no longer required. |
||||
13 | * |
||||
14 | * Wraps: |
||||
15 | * url string in ViewsService |
||||
16 | * config object in ViewsService |
||||
17 | * user object in ViewsService |
||||
18 | * session object in session lib |
||||
19 | * config object in ElggPlugin::includeFile |
||||
20 | * |
||||
21 | * @access private |
||||
22 | * |
||||
23 | * @package Elgg.Core |
||||
24 | */ |
||||
25 | class DeprecationWrapper implements \ArrayAccess { |
||||
26 | /** @var object */ |
||||
27 | protected $object; |
||||
28 | |||||
29 | /** @var string */ |
||||
30 | protected $string; |
||||
31 | |||||
32 | /** @var string */ |
||||
33 | protected $message; |
||||
34 | |||||
35 | /** @var string */ |
||||
36 | protected $version; |
||||
37 | |||||
38 | /** @var callable */ |
||||
39 | protected $reporter; |
||||
40 | |||||
41 | /** |
||||
42 | * Create the wrapper |
||||
43 | * |
||||
44 | * @param mixed $object The object or string to wrap |
||||
45 | * @param string $message The deprecation message to display when used |
||||
46 | * @param string $version The Elgg version this was deprecated |
||||
47 | * @param callable $reporter function called to report deprecation |
||||
48 | */ |
||||
49 | 4 | public function __construct($object, $message, $version, $reporter = 'elgg_deprecated_notice') { |
|||
50 | 4 | if (is_object($object)) { |
|||
51 | 3 | $this->object = $object; |
|||
52 | } else { |
||||
53 | 1 | $this->string = $object; |
|||
54 | } |
||||
55 | 4 | $this->message = $message; |
|||
56 | 4 | $this->version = $version; |
|||
57 | 4 | $this->reporter = $reporter; |
|||
0 ignored issues
–
show
|
|||||
58 | 4 | } |
|||
59 | |||||
60 | /** |
||||
61 | * Get a property on the object |
||||
62 | * |
||||
63 | * @param string $name Property name |
||||
64 | * @return mixed |
||||
65 | */ |
||||
66 | 1 | public function __get($name) { |
|||
67 | 1 | $this->displayWarning(); |
|||
68 | 1 | return $this->object->$name; |
|||
69 | } |
||||
70 | |||||
71 | /** |
||||
72 | * Set a property on the object |
||||
73 | * |
||||
74 | * @param string $name Property name |
||||
75 | * @param mixed $value Property value |
||||
76 | * @return void |
||||
77 | */ |
||||
78 | public function __set($name, $value) { |
||||
79 | $this->displayWarning(); |
||||
80 | $this->object->$name = $value; |
||||
81 | } |
||||
82 | |||||
83 | /** |
||||
84 | * Is a property set? |
||||
85 | * |
||||
86 | * @param string $name Property name |
||||
87 | * @return bool |
||||
88 | */ |
||||
89 | public function __isset($name) { |
||||
90 | $this->displayWarning(); |
||||
91 | return isset($this->object->$name); |
||||
92 | } |
||||
93 | |||||
94 | /** |
||||
95 | * Call a method on the object |
||||
96 | * |
||||
97 | * @param string $name Method name |
||||
98 | * @param array $arguments Method arguments |
||||
99 | * @return mixed |
||||
100 | */ |
||||
101 | 1 | public function __call($name, $arguments) { |
|||
102 | 1 | $this->displayWarning(); |
|||
103 | 1 | return call_user_func_array([$this->object, $name], $arguments); |
|||
104 | } |
||||
105 | |||||
106 | /** |
||||
107 | * Get the object as string |
||||
108 | * |
||||
109 | * @return string |
||||
110 | */ |
||||
111 | 2 | public function __toString() { |
|||
112 | 2 | $this->displayWarning(); |
|||
113 | 2 | if (isset($this->string)) { |
|||
114 | 1 | return $this->string; |
|||
115 | } else { |
||||
116 | 1 | return (string) $this->object; |
|||
117 | } |
||||
118 | } |
||||
119 | |||||
120 | /** |
||||
121 | * Display a warning |
||||
122 | * |
||||
123 | * @return void |
||||
124 | */ |
||||
125 | 4 | protected function displayWarning() { |
|||
126 | // display 3 levels in the function stack to get back to original use |
||||
127 | // 1 for __get/__call/__toString() |
||||
128 | // 1 for displayWarning() |
||||
129 | // 1 for call_user_func() |
||||
130 | 4 | call_user_func($this->reporter, $this->message, $this->version, 3); |
|||
131 | 4 | } |
|||
132 | |||||
133 | /** |
||||
134 | * Array access interface |
||||
135 | * |
||||
136 | * @see \ArrayAccess::offsetSet() |
||||
137 | * |
||||
138 | * @param mixed $key Name |
||||
139 | * @param mixed $value Value |
||||
140 | * |
||||
141 | * @return void |
||||
142 | */ |
||||
143 | 2 | public function offsetSet($key, $value) { |
|||
144 | 2 | $this->displayWarning(); |
|||
145 | 2 | if (is_object($this->object) && !$this->object instanceof \ArrayAccess) { |
|||
146 | 1 | $this->object->$key = $value; |
|||
147 | } else { |
||||
148 | 1 | if ($key === null) { |
|||
149 | // Yes this is necessary. Otherwise $key will be interpreted as empty string |
||||
150 | 1 | $this->object[] = $value; |
|||
151 | } else { |
||||
152 | 1 | $this->object[$key] = $value; |
|||
153 | } |
||||
154 | } |
||||
155 | 2 | } |
|||
156 | |||||
157 | /** |
||||
158 | * Array access interface |
||||
159 | * |
||||
160 | * @see \ArrayAccess::offsetGet() |
||||
161 | * |
||||
162 | * @param mixed $key Name |
||||
163 | * |
||||
164 | * @return mixed |
||||
165 | */ |
||||
166 | 2 | public function offsetGet($key) { |
|||
167 | 2 | $this->displayWarning(); |
|||
168 | 2 | if (is_object($this->object) && !$this->object instanceof \ArrayAccess) { |
|||
169 | 1 | return $this->object->$key; |
|||
170 | } else { |
||||
171 | 1 | return $this->object[$key]; |
|||
172 | } |
||||
173 | } |
||||
174 | |||||
175 | /** |
||||
176 | * Array access interface |
||||
177 | * |
||||
178 | * @see \ArrayAccess::offsetUnset() |
||||
179 | * |
||||
180 | * @param mixed $key Name |
||||
181 | * |
||||
182 | * @return void |
||||
183 | */ |
||||
184 | 1 | public function offsetUnset($key) { |
|||
185 | 1 | $this->displayWarning(); |
|||
186 | 1 | if (is_object($this->object) && !$this->object instanceof \ArrayAccess) { |
|||
187 | unset($this->object->$key); |
||||
188 | } else { |
||||
189 | 1 | unset($this->object[$key]); |
|||
190 | } |
||||
191 | 1 | } |
|||
192 | |||||
193 | /** |
||||
194 | * Array access interface |
||||
195 | * |
||||
196 | * @see \ArrayAccess::offsetExists() |
||||
197 | * |
||||
198 | * @param mixed $offset Offset |
||||
199 | * |
||||
200 | * @return bool |
||||
201 | */ |
||||
202 | public function offsetExists($offset) { |
||||
203 | $this->displayWarning(); |
||||
204 | if (is_object($this->object) && !$this->object instanceof \ArrayAccess) { |
||||
205 | return isset($this->object->$offset); |
||||
206 | } else { |
||||
207 | return array_key_exists($offset, $this->object); |
||||
0 ignored issues
–
show
It seems like
$this->object can also be of type ArrayAccess ; however, parameter $search of array_key_exists() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
208 | } |
||||
209 | } |
||||
210 | } |
||||
211 | |||||
212 |
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 theid
property of an instance of theAccount
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.