diff --git a/composer.json b/composer.json index 6e6bf2c08..fda3ce8ea 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "icewind/searchdav": "^3.2.0", "icewind/streams": "^0.7.7", "kornrunner/blurhash": "^1.2", - "laravel/serializable-closure": "^1.3.5", + "laravel/serializable-closure": "^2.0.4", "mexitek/phpcolors": "^1.0", "microsoft/azure-storage-blob": "^1.5.4", "mlocati/ip-lib": "^1.18", diff --git a/composer.lock b/composer.lock index 5661d5da1..49963723a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "94bf4080c664bd5500e2e31da8ba6852", + "content-hash": "a32759f5cb978838e5ed625c05cc61eb", "packages": [ { "name": "aws/aws-crt-php", @@ -1682,32 +1682,32 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.5", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c" + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c", - "reference": "1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", "shasum": "" }, "require": { - "php": "^7.3|^8.0" + "php": "^8.1" }, "require-dev": { - "illuminate/support": "^8.0|^9.0|^10.0|^11.0", - "nesbot/carbon": "^2.61|^3.0", - "pestphp/pest": "^1.21.3", - "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0" + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -1739,7 +1739,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-09-23T13:33:08+00:00" + "time": "2025-03-19T13:51:03+00:00" }, { "name": "lcobucci/clock", diff --git a/composer/installed.json b/composer/installed.json index d2e803f92..19aaf6c95 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -1745,34 +1745,34 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.5", - "version_normalized": "1.3.5.0", + "version": "v2.0.4", + "version_normalized": "2.0.4.0", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c" + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c", - "reference": "1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", "shasum": "" }, "require": { - "php": "^7.3|^8.0" + "php": "^8.1" }, "require-dev": { - "illuminate/support": "^8.0|^9.0|^10.0|^11.0", - "nesbot/carbon": "^2.61|^3.0", - "pestphp/pest": "^1.21.3", - "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0" + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" }, - "time": "2024-09-23T13:33:08+00:00", + "time": "2025-03-19T13:51:03+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.x-dev" } }, "installation-source": "dist", diff --git a/composer/installed.php b/composer/installed.php index 244d6c302..4cab41f98 100644 --- a/composer/installed.php +++ b/composer/installed.php @@ -218,9 +218,9 @@ 'dev_requirement' => false, ), 'laravel/serializable-closure' => array( - 'pretty_version' => 'v1.3.5', - 'version' => '1.3.5.0', - 'reference' => '1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c', + 'pretty_version' => 'v2.0.4', + 'version' => '2.0.4.0', + 'reference' => 'b352cf0534aa1ae6b4d825d1e762e35d43f8a841', 'type' => 'library', 'install_path' => __DIR__ . '/../laravel/serializable-closure', 'aliases' => array(), diff --git a/laravel/serializable-closure/src/SerializableClosure.php b/laravel/serializable-closure/src/SerializableClosure.php index 86422f935..83a96320c 100644 --- a/laravel/serializable-closure/src/SerializableClosure.php +++ b/laravel/serializable-closure/src/SerializableClosure.php @@ -4,7 +4,6 @@ use Closure; use Laravel\SerializableClosure\Exceptions\InvalidSignatureException; -use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException; use Laravel\SerializableClosure\Serializers\Signed; use Laravel\SerializableClosure\Signers\Hmac; @@ -25,10 +24,6 @@ class SerializableClosure */ public function __construct(Closure $closure) { - if (\PHP_VERSION_ID < 70400) { - throw new PhpVersionNotSupportedException(); - } - $this->serializable = Serializers\Signed::$signer ? new Serializers\Signed($closure) : new Serializers\Native($closure); @@ -41,10 +36,6 @@ public function __construct(Closure $closure) */ public function __invoke() { - if (\PHP_VERSION_ID < 70400) { - throw new PhpVersionNotSupportedException(); - } - return call_user_func_array($this->serializable, func_get_args()); } @@ -55,10 +46,6 @@ public function __invoke() */ public function getClosure() { - if (\PHP_VERSION_ID < 70400) { - throw new PhpVersionNotSupportedException(); - } - return $this->serializable->getClosure(); } @@ -111,7 +98,7 @@ public static function resolveUseVariablesUsing($resolver) /** * Get the serializable representation of the closure. * - * @return array + * @return array{serializable: \Laravel\SerializableClosure\Serializers\Signed|\Laravel\SerializableClosure\Contracts\Serializable} */ public function __serialize() { @@ -123,7 +110,7 @@ public function __serialize() /** * Restore the closure after serialization. * - * @param array $data + * @param array{serializable: \Laravel\SerializableClosure\Serializers\Signed|\Laravel\SerializableClosure\Contracts\Serializable} $data * @return void * * @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException diff --git a/laravel/serializable-closure/src/Serializers/Native.php b/laravel/serializable-closure/src/Serializers/Native.php index 59a1bc6cc..6fe884bb5 100644 --- a/laravel/serializable-closure/src/Serializers/Native.php +++ b/laravel/serializable-closure/src/Serializers/Native.php @@ -12,6 +12,7 @@ use Laravel\SerializableClosure\Support\SelfReference; use Laravel\SerializableClosure\UnsignedSerializableClosure; use ReflectionObject; +use ReflectionProperty; use UnitEnum; class Native implements Serializable @@ -274,7 +275,7 @@ public static function wrapClosures(&$data, $storage) $property->setAccessible(true); - if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) { + if (! $property->isInitialized($instance)) { continue; } @@ -374,11 +375,7 @@ protected function mapPointers(&$data) $property->setAccessible(true); - if (PHP_VERSION >= 7.4 && ! $property->isInitialized($data)) { - continue; - } - - if (PHP_VERSION >= 8.1 && $property->isReadOnly()) { + if (! $property->isInitialized($data) || $property->isReadOnly()) { continue; } @@ -494,13 +491,13 @@ protected function mapByReference(&$data) } foreach ($reflection->getProperties() as $property) { - if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) { + if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined() || $this->isVirtualProperty($property)) { continue; } $property->setAccessible(true); - if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) { + if (! $property->isInitialized($instance) || ($property->isReadOnly() && $property->class !== $reflection->name)) { continue; } @@ -515,4 +512,15 @@ protected function mapByReference(&$data) } while ($reflection = $reflection->getParentClass()); } } + + /** + * Determine is virtual property. + * + * @param \ReflectionProperty $property + * @return bool + */ + protected function isVirtualProperty(ReflectionProperty $property): bool + { + return method_exists($property, 'isVirtual') && $property->isVirtual(); + } } diff --git a/laravel/serializable-closure/src/Serializers/Signed.php b/laravel/serializable-closure/src/Serializers/Signed.php index 391d20d67..16f9593f5 100644 --- a/laravel/serializable-closure/src/Serializers/Signed.php +++ b/laravel/serializable-closure/src/Serializers/Signed.php @@ -72,7 +72,7 @@ public function __serialize() /** * Restore the closure after serialization. * - * @param array $signature + * @param array{serializable: string, hash: string} $signature * @return void * * @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException diff --git a/laravel/serializable-closure/src/Signers/Hmac.php b/laravel/serializable-closure/src/Signers/Hmac.php index d94b0a2a3..41ed01ae8 100644 --- a/laravel/serializable-closure/src/Signers/Hmac.php +++ b/laravel/serializable-closure/src/Signers/Hmac.php @@ -41,7 +41,7 @@ public function sign($serialized) /** * Verify the given signature. * - * @param array $signature + * @param array{serializable: string, hash: string} $signature * @return bool */ public function verify($signature) diff --git a/laravel/serializable-closure/src/Support/ClosureStream.php b/laravel/serializable-closure/src/Support/ClosureStream.php index 9f3ef6c8b..717ae053f 100644 --- a/laravel/serializable-closure/src/Support/ClosureStream.php +++ b/laravel/serializable-closure/src/Support/ClosureStream.php @@ -7,6 +7,8 @@ class ClosureStream { /** * The stream protocol. + * + * @var string */ const STREAM_PROTO = 'laravel-serializable-closure'; diff --git a/laravel/serializable-closure/src/Support/ReflectionClosure.php b/laravel/serializable-closure/src/Support/ReflectionClosure.php index e489996bb..fb90bef08 100644 --- a/laravel/serializable-closure/src/Support/ReflectionClosure.php +++ b/laravel/serializable-closure/src/Support/ReflectionClosure.php @@ -508,7 +508,7 @@ public function getCode() break; case 'id_name': switch ($token[0]) { - case $token[0] === ':' && $context !== 'instanceof': + case $token[0] === ':' && ! in_array($context, ['instanceof', 'new'], true): if ($lastState === 'closure' && $context === 'root') { $state = 'closure'; $code .= $id_start.$token; @@ -680,27 +680,25 @@ public function getCode() $this->isBindingRequired = $isUsingThisObject; $this->isScopeRequired = $isUsingScope; - if (PHP_VERSION_ID >= 80100) { - $attributesCode = array_map(function ($attribute) { - $arguments = $attribute->getArguments(); + $attributesCode = array_map(function ($attribute) { + $arguments = $attribute->getArguments(); - $name = $attribute->getName(); - $arguments = implode(', ', array_map(function ($argument, $key) { - $argument = sprintf("'%s'", str_replace("'", "\\'", $argument)); + $name = $attribute->getName(); + $arguments = implode(', ', array_map(function ($argument, $key) { + $argument = sprintf("'%s'", str_replace("'", "\\'", $argument)); - if (is_string($key)) { - $argument = sprintf('%s: %s', $key, $argument); - } + if (is_string($key)) { + $argument = sprintf('%s: %s', $key, $argument); + } - return $argument; - }, $arguments, array_keys($arguments))); + return $argument; + }, $arguments, array_keys($arguments))); - return "#[$name($arguments)]"; - }, $this->getAttributes()); + return "#[$name($arguments)]"; + }, $this->getAttributes()); - if (! empty($attributesCode)) { - $code = implode("\n", array_merge($attributesCode, [$code])); - } + if (! empty($attributesCode)) { + $code = implode("\n", array_merge($attributesCode, [$code])); } $this->code = $code; @@ -715,25 +713,7 @@ public function getCode() */ protected static function getBuiltinTypes() { - // PHP 8.1 - if (PHP_VERSION_ID >= 80100) { - return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null', 'never']; - } - - // PHP 8 - if (\PHP_MAJOR_VERSION === 8) { - return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null']; - } - - // PHP 7 - switch (\PHP_MINOR_VERSION) { - case 0: - return ['array', 'callable', 'string', 'int', 'bool', 'float']; - case 1: - return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void']; - default: - return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object']; - } + return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null', 'never']; } /** @@ -806,7 +786,7 @@ public function isScopeRequired() } /** - * The the hash of the current file name. + * The hash of the current file name. * * @return string */ @@ -885,13 +865,18 @@ protected function getTokens() */ protected function getClasses() { - $key = $this->getHashedFileName(); - - if (! isset(static::$classes[$key])) { - $this->fetchItems(); + $line = $this->getStartLine(); + + foreach ($this->getStructures() as $struct) { + if ($struct['type'] === 'namespace' && + $struct['start'] <= $line && + $struct['end'] >= $line + ) { + return $struct['classes']; + } } - return static::$classes[$key]; + return []; } /** @@ -965,14 +950,36 @@ protected function fetchItems() $alias = ''; $isFunc = $isConst = false; - $startLine = $endLine = 0; + $startLine = $lastKnownLine = 0; $structType = $structName = ''; $structIgnore = false; + $namespace = ''; + $namespaceStartLine = 0; + $namespaceBraced = false; + $namespaceClasses = []; + foreach ($tokens as $token) { + if (is_array($token)) { + $lastKnownLine = $token[2]; + } + switch ($state) { case 'start': switch ($token[0]) { + case T_NAMESPACE: + $structures[] = [ + 'type' => 'namespace', + 'name' => $namespace, + 'start' => $namespaceStartLine, + 'end' => $token[2] - 1, + 'classes' => $namespaceClasses, + ]; + $namespace = ''; + $namespaceClasses = []; + $state = 'namespace'; + $namespaceStartLine = $token[2]; + break; case T_CLASS: case T_INTERFACE: case T_TRAIT: @@ -998,6 +1005,33 @@ protected function fetchItems() case T_DOUBLE_COLON: $state = 'invoke'; break; + case '}': + if ($namespaceBraced) { + $structures[] = [ + 'type' => 'namespace', + 'name' => $namespace, + 'start' => $namespaceStartLine, + 'end' => $lastKnownLine, + 'classes' => $namespaceClasses, + ]; + $namespaceBraced = false; + $namespace = ''; + $namespaceClasses = []; + } + break; + } + break; + case 'namespace': + switch ($token[0]) { + case T_STRING: + case T_NAME_QUALIFIED: + $namespace = $token[1]; + break; + case ';': + case '{': + $state = 'start'; + $namespaceBraced = $token[0] === '{'; + break; } break; case 'use': @@ -1042,6 +1076,7 @@ protected function fetchItems() $constants[$alias] = $name; } else { $classes[strtolower($alias)] = $name; + $namespaceClasses[strtolower($alias)] = $name; } } $name = $alias = ''; @@ -1081,6 +1116,7 @@ protected function fetchItems() $constants[$alias] = $prefix.$name; } else { $classes[strtolower($alias)] = $prefix.$name; + $namespaceClasses[strtolower($alias)] = $prefix.$name; } } $name = $alias = ''; @@ -1138,22 +1174,26 @@ protected function fetchItems() 'type' => $structType, 'name' => $structName, 'start' => $startLine, - 'end' => $endLine, + 'end' => $lastKnownLine, ]; } $structIgnore = false; $state = 'start'; } break; - default: - if (is_array($token)) { - $endLine = $token[2]; - } } break; } } + $structures[] = [ + 'type' => 'namespace', + 'name' => $namespace, + 'start' => $namespaceStartLine, + 'end' => PHP_INT_MAX, + 'classes' => $namespaceClasses, + ]; + static::$classes[$key] = $classes; static::$functions[$key] = $functions; static::$constants[$key] = $constants; @@ -1167,14 +1207,19 @@ protected function fetchItems() */ protected function getClosureNamespaceName() { - $ns = $this->getNamespaceName(); - - // First class callables... - if ($this->getName() !== '{closure}' && empty($ns) && ! is_null($this->getClosureScopeClass())) { - $ns = $this->getClosureScopeClass()->getNamespaceName(); + $startLine = $this->getStartLine(); + $endLine = $this->getEndLine(); + + foreach ($this->getStructures() as $struct) { + if ($struct['type'] === 'namespace' && + $struct['start'] <= $startLine && + $struct['end'] >= $endLine + ) { + return $struct['name']; + } } - return $ns; + return ''; } /** diff --git a/laravel/serializable-closure/src/UnsignedSerializableClosure.php b/laravel/serializable-closure/src/UnsignedSerializableClosure.php index 1588e7cc0..afc2127ed 100644 --- a/laravel/serializable-closure/src/UnsignedSerializableClosure.php +++ b/laravel/serializable-closure/src/UnsignedSerializableClosure.php @@ -3,7 +3,6 @@ namespace Laravel\SerializableClosure; use Closure; -use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException; class UnsignedSerializableClosure { @@ -22,10 +21,6 @@ class UnsignedSerializableClosure */ public function __construct(Closure $closure) { - if (\PHP_VERSION_ID < 70400) { - throw new PhpVersionNotSupportedException(); - } - $this->serializable = new Serializers\Native($closure); } @@ -36,10 +31,6 @@ public function __construct(Closure $closure) */ public function __invoke() { - if (\PHP_VERSION_ID < 70400) { - throw new PhpVersionNotSupportedException(); - } - return call_user_func_array($this->serializable, func_get_args()); } @@ -50,17 +41,13 @@ public function __invoke() */ public function getClosure() { - if (\PHP_VERSION_ID < 70400) { - throw new PhpVersionNotSupportedException(); - } - return $this->serializable->getClosure(); } /** * Get the serializable representation of the closure. * - * @return array + * @return array{serializable: \Laravel\SerializableClosure\Contracts\Serializable} */ public function __serialize() { @@ -72,7 +59,7 @@ public function __serialize() /** * Restore the closure after serialization. * - * @param array $data + * @param array{serializable: \Laravel\SerializableClosure\Contracts\Serializable} $data * @return void */ public function __unserialize($data)