PluginProbe
Elementor Website Builder – more than just a page builder / 3.25.1
Elementor Website Builder – more than just a page builder v3.25.1
4.3.2 4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 All 455 releases
elementor / vendor_prefixed / laravel / serializable-closure / src / Serializers / Native.php

Native.php in Elementor Website Builder – more than just a page builder 3.25.1, at vendor_prefixed/laravel/serializable-closure/src/Serializers/Native.php

400 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ElementorDeps\Laravel\SerializableClosure\Serializers;
4
5 use Closure;
6 use DateTimeInterface;
7 use ElementorDeps\Laravel\SerializableClosure\Contracts\Serializable;
8 use ElementorDeps\Laravel\SerializableClosure\SerializableClosure;
9 use ElementorDeps\Laravel\SerializableClosure\Support\ClosureScope;
10 use ElementorDeps\Laravel\SerializableClosure\Support\ClosureStream;
11 use ElementorDeps\Laravel\SerializableClosure\Support\ReflectionClosure;
12 use ElementorDeps\Laravel\SerializableClosure\Support\SelfReference;
13 use ElementorDeps\Laravel\SerializableClosure\UnsignedSerializableClosure;
14 use ReflectionObject;
15 use UnitEnum;
16 class Native implements Serializable
17 {
18 /**
19 * Transform the use variables before serialization.
20 *
21 * @var \Closure|null
22 */
23 public static $transformUseVariables;
24 /**
25 * Resolve the use variables after unserialization.
26 *
27 * @var \Closure|null
28 */
29 public static $resolveUseVariables;
30 /**
31 * The closure to be serialized/unserialized.
32 *
33 * @var \Closure
34 */
35 protected $closure;
36 /**
37 * The closure's reflection.
38 *
39 * @var \Laravel\SerializableClosure\Support\ReflectionClosure|null
40 */
41 protected $reflector;
42 /**
43 * The closure's code.
44 *
45 * @var array|null
46 */
47 protected $code;
48 /**
49 * The closure's reference.
50 *
51 * @var string
52 */
53 protected $reference;
54 /**
55 * The closure's scope.
56 *
57 * @var \Laravel\SerializableClosure\Support\ClosureScope|null
58 */
59 protected $scope;
60 /**
61 * The "key" that marks an array as recursive.
62 */
63 const ARRAY_RECURSIVE_KEY = 'LARAVEL_SERIALIZABLE_RECURSIVE_KEY';
64 /**
65 * Creates a new serializable closure instance.
66 *
67 * @param \Closure $closure
68 * @return void
69 */
70 public function __construct(Closure $closure)
71 {
72 $this->closure = $closure;
73 }
74 /**
75 * Resolve the closure with the given arguments.
76 *
77 * @return mixed
78 */
79 public function __invoke()
80 {
81 return \call_user_func_array($this->closure, \func_get_args());
82 }
83 /**
84 * Gets the closure.
85 *
86 * @return \Closure
87 */
88 public function getClosure()
89 {
90 return $this->closure;
91 }
92 /**
93 * Get the serializable representation of the closure.
94 *
95 * @return array
96 */
97 public function __serialize()
98 {
99 if ($this->scope === null) {
100 $this->scope = new ClosureScope();
101 $this->scope->toSerialize++;
102 }
103 $this->scope->serializations++;
104 $scope = $object = null;
105 $reflector = $this->getReflector();
106 if ($reflector->isBindingRequired()) {
107 $object = $reflector->getClosureThis();
108 static::wrapClosures($object, $this->scope);
109 }
110 if ($scope = $reflector->getClosureScopeClass()) {
111 $scope = $scope->name;
112 }
113 $this->reference = \spl_object_hash($this->closure);
114 $this->scope[$this->closure] = $this;
115 $use = $reflector->getUseVariables();
116 if (static::$transformUseVariables) {
117 $use = \call_user_func(static::$transformUseVariables, $reflector->getUseVariables());
118 }
119 $code = $reflector->getCode();
120 $this->mapByReference($use);
121 $data = ['use' => $use, 'function' => $code, 'scope' => $scope, 'this' => $object, 'self' => $this->reference];
122 if (!--$this->scope->serializations && !--$this->scope->toSerialize) {
123 $this->scope = null;
124 }
125 return $data;
126 }
127 /**
128 * Restore the closure after serialization.
129 *
130 * @param array $data
131 * @return void
132 */
133 public function __unserialize($data)
134 {
135 ClosureStream::register();
136 $this->code = $data;
137 unset($data);
138 $this->code['objects'] = [];
139 if ($this->code['use']) {
140 $this->scope = new ClosureScope();
141 if (static::$resolveUseVariables) {
142 $this->code['use'] = \call_user_func(static::$resolveUseVariables, $this->code['use']);
143 }
144 $this->mapPointers($this->code['use']);
145 \extract($this->code['use'], \EXTR_OVERWRITE | \EXTR_REFS);
146 $this->scope = null;
147 }
148 $this->closure = (include ClosureStream::STREAM_PROTO . '://' . $this->code['function']);
149 if ($this->code['this'] === $this) {
150 $this->code['this'] = null;
151 }
152 $this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']);
153 if (!empty($this->code['objects'])) {
154 foreach ($this->code['objects'] as $item) {
155 $item['property']->setValue($item['instance'], $item['object']->getClosure());
156 }
157 }
158 $this->code = $this->code['function'];
159 }
160 /**
161 * Ensures the given closures are serializable.
162 *
163 * @param mixed $data
164 * @param \Laravel\SerializableClosure\Support\ClosureScope $storage
165 * @return void
166 */
167 public static function wrapClosures(&$data, $storage)
168 {
169 if ($data instanceof Closure) {
170 $data = new static($data);
171 } elseif (\is_array($data)) {
172 if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
173 return;
174 }
175 $data[self::ARRAY_RECURSIVE_KEY] = \true;
176 foreach ($data as $key => &$value) {
177 if ($key === self::ARRAY_RECURSIVE_KEY) {
178 continue;
179 }
180 static::wrapClosures($value, $storage);
181 }
182 unset($value);
183 unset($data[self::ARRAY_RECURSIVE_KEY]);
184 } elseif ($data instanceof \stdClass) {
185 if (isset($storage[$data])) {
186 $data = $storage[$data];
187 return;
188 }
189 $data = $storage[$data] = clone $data;
190 foreach ($data as &$value) {
191 static::wrapClosures($value, $storage);
192 }
193 unset($value);
194 } elseif (\is_object($data) && !$data instanceof static && !$data instanceof UnitEnum) {
195 if (isset($storage[$data])) {
196 $data = $storage[$data];
197 return;
198 }
199 $instance = $data;
200 $reflection = new ReflectionObject($instance);
201 if (!$reflection->isUserDefined()) {
202 $storage[$instance] = $data;
203 return;
204 }
205 $storage[$instance] = $data = $reflection->newInstanceWithoutConstructor();
206 do {
207 if (!$reflection->isUserDefined()) {
208 break;
209 }
210 foreach ($reflection->getProperties() as $property) {
211 if ($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()) {
212 continue;
213 }
214 $property->setAccessible(\true);
215 if (\PHP_VERSION >= 7.4 && !$property->isInitialized($instance)) {
216 continue;
217 }
218 $value = $property->getValue($instance);
219 if (\is_array($value) || \is_object($value)) {
220 static::wrapClosures($value, $storage);
221 }
222 $property->setValue($data, $value);
223 }
224 } while ($reflection = $reflection->getParentClass());
225 }
226 }
227 /**
228 * Gets the closure's reflector.
229 *
230 * @return \Laravel\SerializableClosure\Support\ReflectionClosure
231 */
232 public function getReflector()
233 {
234 if ($this->reflector === null) {
235 $this->code = null;
236 $this->reflector = new ReflectionClosure($this->closure);
237 }
238 return $this->reflector;
239 }
240 /**
241 * Internal method used to map closure pointers.
242 *
243 * @param mixed $data
244 * @return void
245 */
246 protected function mapPointers(&$data)
247 {
248 $scope = $this->scope;
249 if ($data instanceof static) {
250 $data =& $data->closure;
251 } elseif (\is_array($data)) {
252 if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
253 return;
254 }
255 $data[self::ARRAY_RECURSIVE_KEY] = \true;
256 foreach ($data as $key => &$value) {
257 if ($key === self::ARRAY_RECURSIVE_KEY) {
258 continue;
259 } elseif ($value instanceof static) {
260 $data[$key] =& $value->closure;
261 } elseif ($value instanceof SelfReference && $value->hash === $this->code['self']) {
262 $data[$key] =& $this->closure;
263 } else {
264 $this->mapPointers($value);
265 }
266 }
267 unset($value);
268 unset($data[self::ARRAY_RECURSIVE_KEY]);
269 } elseif ($data instanceof \stdClass) {
270 if (isset($scope[$data])) {
271 return;
272 }
273 $scope[$data] = \true;
274 foreach ($data as $key => &$value) {
275 if ($value instanceof SelfReference && $value->hash === $this->code['self']) {
276 $data->{$key} =& $this->closure;
277 } elseif (\is_array($value) || \is_object($value)) {
278 $this->mapPointers($value);
279 }
280 }
281 unset($value);
282 } elseif (\is_object($data) && !$data instanceof Closure) {
283 if (isset($scope[$data])) {
284 return;
285 }
286 $scope[$data] = \true;
287 $reflection = new ReflectionObject($data);
288 do {
289 if (!$reflection->isUserDefined()) {
290 break;
291 }
292 foreach ($reflection->getProperties() as $property) {
293 if ($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()) {
294 continue;
295 }
296 $property->setAccessible(\true);
297 if (\PHP_VERSION >= 7.4 && !$property->isInitialized($data)) {
298 continue;
299 }
300 if (\PHP_VERSION >= 8.1 && $property->isReadOnly()) {
301 continue;
302 }
303 $item = $property->getValue($data);
304 if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || $item instanceof SelfReference && $item->hash === $this->code['self']) {
305 $this->code['objects'][] = ['instance' => $data, 'property' => $property, 'object' => $item instanceof SelfReference ? $this : $item];
306 } elseif (\is_array($item) || \is_object($item)) {
307 $this->mapPointers($item);
308 $property->setValue($data, $item);
309 }
310 }
311 } while ($reflection = $reflection->getParentClass());
312 }
313 }
314 /**
315 * Internal method used to map closures by reference.
316 *
317 * @param mixed $data
318 * @return void
319 */
320 protected function mapByReference(&$data)
321 {
322 if ($data instanceof Closure) {
323 if ($data === $this->closure) {
324 $data = new SelfReference($this->reference);
325 return;
326 }
327 if (isset($this->scope[$data])) {
328 $data = $this->scope[$data];
329 return;
330 }
331 $instance = new static($data);
332 $instance->scope = $this->scope;
333 $data = $this->scope[$data] = $instance;
334 } elseif (\is_array($data)) {
335 if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
336 return;
337 }
338 $data[self::ARRAY_RECURSIVE_KEY] = \true;
339 foreach ($data as $key => &$value) {
340 if ($key === self::ARRAY_RECURSIVE_KEY) {
341 continue;
342 }
343 $this->mapByReference($value);
344 }
345 unset($value);
346 unset($data[self::ARRAY_RECURSIVE_KEY]);
347 } elseif ($data instanceof \stdClass) {
348 if (isset($this->scope[$data])) {
349 $data = $this->scope[$data];
350 return;
351 }
352 $instance = $data;
353 $this->scope[$instance] = $data = clone $data;
354 foreach ($data as &$value) {
355 $this->mapByReference($value);
356 }
357 unset($value);
358 } elseif (\is_object($data) && !$data instanceof SerializableClosure && !$data instanceof UnsignedSerializableClosure) {
359 if (isset($this->scope[$data])) {
360 $data = $this->scope[$data];
361 return;
362 }
363 $instance = $data;
364 if ($data instanceof DateTimeInterface) {
365 $this->scope[$instance] = $data;
366 return;
367 }
368 if ($data instanceof UnitEnum) {
369 $this->scope[$instance] = $data;
370 return;
371 }
372 $reflection = new ReflectionObject($data);
373 if (!$reflection->isUserDefined()) {
374 $this->scope[$instance] = $data;
375 return;
376 }
377 $this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor();
378 do {
379 if (!$reflection->isUserDefined()) {
380 break;
381 }
382 foreach ($reflection->getProperties() as $property) {
383 if ($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()) {
384 continue;
385 }
386 $property->setAccessible(\true);
387 if (\PHP_VERSION >= 7.4 && !$property->isInitialized($instance)) {
388 continue;
389 }
390 $value = $property->getValue($instance);
391 if (\is_array($value) || \is_object($value)) {
392 $this->mapByReference($value);
393 }
394 $property->setValue($data, $value);
395 }
396 } while ($reflection = $reflection->getParentClass());
397 }
398 }
399 }
400