File Editor
Directories:
.. (Back)
Files:
Native.php
Signed.php
Create New File
Create
Edit File: Native.php
<?php namespace ElementorDeps\Laravel\SerializableClosure\Serializers; use Closure; use DateTimeInterface; use ElementorDeps\Laravel\SerializableClosure\Contracts\Serializable; use ElementorDeps\Laravel\SerializableClosure\SerializableClosure; use ElementorDeps\Laravel\SerializableClosure\Support\ClosureScope; use ElementorDeps\Laravel\SerializableClosure\Support\ClosureStream; use ElementorDeps\Laravel\SerializableClosure\Support\ReflectionClosure; use ElementorDeps\Laravel\SerializableClosure\Support\SelfReference; use ElementorDeps\Laravel\SerializableClosure\UnsignedSerializableClosure; use ReflectionObject; use UnitEnum; class Native implements Serializable { /** * Transform the use variables before serialization. * * @var \Closure|null */ public static $transformUseVariables; /** * Resolve the use variables after unserialization. * * @var \Closure|null */ public static $resolveUseVariables; /** * The closure to be serialized/unserialized. * * @var \Closure */ protected $closure; /** * The closure's reflection. * * @var \Laravel\SerializableClosure\Support\ReflectionClosure|null */ protected $reflector; /** * The closure's code. * * @var array|null */ protected $code; /** * The closure's reference. * * @var string */ protected $reference; /** * The closure's scope. * * @var \Laravel\SerializableClosure\Support\ClosureScope|null */ protected $scope; /** * The "key" that marks an array as recursive. */ const ARRAY_RECURSIVE_KEY = 'LARAVEL_SERIALIZABLE_RECURSIVE_KEY'; /** * Creates a new serializable closure instance. * * @param \Closure $closure * @return void */ public function __construct(Closure $closure) { $this->closure = $closure; } /** * Resolve the closure with the given arguments. * * @return mixed */ public function __invoke() { return \call_user_func_array($this->closure, \func_get_args()); } /** * Gets the closure. * * @return \Closure */ public function getClosure() { return $this->closure; } /** * Get the serializable representation of the closure. * * @return array */ public function __serialize() { if ($this->scope === null) { $this->scope = new ClosureScope(); $this->scope->toSerialize++; } $this->scope->serializations++; $scope = $object = null; $reflector = $this->getReflector(); if ($reflector->isBindingRequired()) { $object = $reflector->getClosureThis(); static::wrapClosures($object, $this->scope); } if ($scope = $reflector->getClosureScopeClass()) { $scope = $scope->name; } $this->reference = \spl_object_hash($this->closure); $this->scope[$this->closure] = $this; $use = $reflector->getUseVariables(); if (static::$transformUseVariables) { $use = \call_user_func(static::$transformUseVariables, $reflector->getUseVariables()); } $code = $reflector->getCode(); $this->mapByReference($use); $data = ['use' => $use, 'function' => $code, 'scope' => $scope, 'this' => $object, 'self' => $this->reference]; if (!--$this->scope->serializations && !--$this->scope->toSerialize) { $this->scope = null; } return $data; } /** * Restore the closure after serialization. * * @param array $data * @return void */ public function __unserialize($data) { ClosureStream::register(); $this->code = $data; unset($data); $this->code['objects'] = []; if ($this->code['use']) { $this->scope = new ClosureScope(); if (static::$resolveUseVariables) { $this->code['use'] = \call_user_func(static::$resolveUseVariables, $this->code['use']); } $this->mapPointers($this->code['use']); \extract($this->code['use'], \EXTR_OVERWRITE | \EXTR_REFS); $this->scope = null; } $this->closure = (include ClosureStream::STREAM_PROTO . '://' . $this->code['function']); if ($this->code['this'] === $this) { $this->code['this'] = null; } $this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']); if (!empty($this->code['objects'])) { foreach ($this->code['objects'] as $item) { $item['property']->setValue($item['instance'], $item['object']->getClosure()); } } $this->code = $this->code['function']; } /** * Ensures the given closures are serializable. * * @param mixed $data * @param \Laravel\SerializableClosure\Support\ClosureScope $storage * @return void */ public static function wrapClosures(&$data, $storage) { if ($data instanceof Closure) { $data = new static($data); } elseif (\is_array($data)) { if (isset($data[self::ARRAY_RECURSIVE_KEY])) { return; } $data[self::ARRAY_RECURSIVE_KEY] = \true; foreach ($data as $key => &$value) { if ($key === self::ARRAY_RECURSIVE_KEY) { continue; } static::wrapClosures($value, $storage); } unset($value); unset($data[self::ARRAY_RECURSIVE_KEY]); } elseif ($data instanceof \stdClass) { if (isset($storage[$data])) { $data = $storage[$data]; return; } $data = $storage[$data] = clone $data; foreach ($data as &$value) { static::wrapClosures($value, $storage); } unset($value); } elseif (\is_object($data) && !$data instanceof static && !$data instanceof UnitEnum) { if (isset($storage[$data])) { $data = $storage[$data]; return; } $instance = $data; $reflection = new ReflectionObject($instance); if (!$reflection->isUserDefined()) { $storage[$instance] = $data; return; } $storage[$instance] = $data = $reflection->newInstanceWithoutConstructor(); do { if (!$reflection->isUserDefined()) { break; } foreach ($reflection->getProperties() as $property) { if ($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()) { continue; } $property->setAccessible(\true); if (\PHP_VERSION >= 7.4 && !$property->isInitialized($instance)) { continue; } $value = $property->getValue($instance); if (\is_array($value) || \is_object($value)) { static::wrapClosures($value, $storage); } $property->setValue($data, $value); } } while ($reflection = $reflection->getParentClass()); } } /** * Gets the closure's reflector. * * @return \Laravel\SerializableClosure\Support\ReflectionClosure */ public function getReflector() { if ($this->reflector === null) { $this->code = null; $this->reflector = new ReflectionClosure($this->closure); } return $this->reflector; } /** * Internal method used to map closure pointers. * * @param mixed $data * @return void */ protected function mapPointers(&$data) { $scope = $this->scope; if ($data instanceof static) { $data =& $data->closure; } elseif (\is_array($data)) { if (isset($data[self::ARRAY_RECURSIVE_KEY])) { return; } $data[self::ARRAY_RECURSIVE_KEY] = \true; foreach ($data as $key => &$value) { if ($key === self::ARRAY_RECURSIVE_KEY) { continue; } elseif ($value instanceof static) { $data[$key] =& $value->closure; } elseif ($value instanceof SelfReference && $value->hash === $this->code['self']) { $data[$key] =& $this->closure; } else { $this->mapPointers($value); } } unset($value); unset($data[self::ARRAY_RECURSIVE_KEY]); } elseif ($data instanceof \stdClass) { if (isset($scope[$data])) { return; } $scope[$data] = \true; foreach ($data as $key => &$value) { if ($value instanceof SelfReference && $value->hash === $this->code['self']) { $data->{$key} =& $this->closure; } elseif (\is_array($value) || \is_object($value)) { $this->mapPointers($value); } } unset($value); } elseif (\is_object($data) && !$data instanceof Closure) { if (isset($scope[$data])) { return; } $scope[$data] = \true; $reflection = new ReflectionObject($data); do { if (!$reflection->isUserDefined()) { break; } foreach ($reflection->getProperties() as $property) { if ($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()) { continue; } $property->setAccessible(\true); if (\PHP_VERSION >= 7.4 && !$property->isInitialized($data)) { continue; } if (\PHP_VERSION >= 8.1 && $property->isReadOnly()) { continue; } $item = $property->getValue($data); if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || $item instanceof SelfReference && $item->hash === $this->code['self']) { $this->code['objects'][] = ['instance' => $data, 'property' => $property, 'object' => $item instanceof SelfReference ? $this : $item]; } elseif (\is_array($item) || \is_object($item)) { $this->mapPointers($item); $property->setValue($data, $item); } } } while ($reflection = $reflection->getParentClass()); } } /** * Internal method used to map closures by reference. * * @param mixed $data * @return void */ protected function mapByReference(&$data) { if ($data instanceof Closure) { if ($data === $this->closure) { $data = new SelfReference($this->reference); return; } if (isset($this->scope[$data])) { $data = $this->scope[$data]; return; } $instance = new static($data); $instance->scope = $this->scope; $data = $this->scope[$data] = $instance; } elseif (\is_array($data)) { if (isset($data[self::ARRAY_RECURSIVE_KEY])) { return; } $data[self::ARRAY_RECURSIVE_KEY] = \true; foreach ($data as $key => &$value) { if ($key === self::ARRAY_RECURSIVE_KEY) { continue; } $this->mapByReference($value); } unset($value); unset($data[self::ARRAY_RECURSIVE_KEY]); } elseif ($data instanceof \stdClass) { if (isset($this->scope[$data])) { $data = $this->scope[$data]; return; } $instance = $data; $this->scope[$instance] = $data = clone $data; foreach ($data as &$value) { $this->mapByReference($value); } unset($value); } elseif (\is_object($data) && !$data instanceof SerializableClosure && !$data instanceof UnsignedSerializableClosure) { if (isset($this->scope[$data])) { $data = $this->scope[$data]; return; } $instance = $data; if ($data instanceof DateTimeInterface) { $this->scope[$instance] = $data; return; } if ($data instanceof UnitEnum) { $this->scope[$instance] = $data; return; } $reflection = new ReflectionObject($data); if (!$reflection->isUserDefined()) { $this->scope[$instance] = $data; return; } $this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor(); do { if (!$reflection->isUserDefined()) { break; } foreach ($reflection->getProperties() as $property) { if ($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()) { continue; } $property->setAccessible(\true); if (\PHP_VERSION >= 7.4 && !$property->isInitialized($instance)) { continue; } $value = $property->getValue($instance); if (\is_array($value) || \is_object($value)) { $this->mapByReference($value); } $property->setValue($data, $value); } } while ($reflection = $reflection->getParentClass()); } } }
Save Changes
Rename File
Rename