PluginProbe
WPIDE – File Manager & Code Editor / 3.5.9
WPIDE – File Manager & Code Editor v3.5.9
3.5.9 3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 All 55 releases
wpide / vendor / laravel / serializable-closure / src / Serializers / Native.php

Native.php in WPIDE – File Manager & Code Editor 3.5.9, at vendor/laravel/serializable-closure/src/Serializers/Native.php

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