From 5d33407155617a2bd7378c73c7e36eabb69fc751 Mon Sep 17 00:00:00 2001 From: kylekatarnls Date: Mon, 20 May 2024 13:29:23 +0200 Subject: [PATCH] [VarExporter] Fix exporting default values involving global constants --- .../Component/VarExporter/ProxyHelper.php | 30 ++++++++++++++----- .../VarExporter/Tests/ProxyHelperTest.php | 5 ++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/VarExporter/ProxyHelper.php b/src/Symfony/Component/VarExporter/ProxyHelper.php index 9105d0c71dadc..8d19d38373ce4 100644 --- a/src/Symfony/Component/VarExporter/ProxyHelper.php +++ b/src/Symfony/Component/VarExporter/ProxyHelper.php @@ -219,12 +219,14 @@ public static function exportSignature(\ReflectionFunctionAbstract $function, bo $args = ''; $param = null; $parameters = []; + $namespace = $function instanceof \ReflectionMethod ? $function->class : $function->getNamespaceName().'\\'; + $namespace = substr($namespace, 0, strrpos($namespace, '\\') ?: 0); foreach ($function->getParameters() as $param) { $parameters[] = ($param->getAttributes(\SensitiveParameter::class) ? '#[\SensitiveParameter] ' : '') .($withParameterTypes && $param->hasType() ? self::exportType($param).' ' : '') .($param->isPassedByReference() ? '&' : '') .($param->isVariadic() ? '...' : '').'$'.$param->name - .($param->isOptional() && !$param->isVariadic() ? ' = '.self::exportDefault($param) : ''); + .($param->isOptional() && !$param->isVariadic() ? ' = '.self::exportDefault($param, $namespace) : ''); if ($param->isPassedByReference()) { $byRefIndex = 1 + $param->getPosition(); } @@ -333,7 +335,7 @@ private static function exportPropertyScopes(string $parent): string return $propertyScopes; } - private static function exportDefault(\ReflectionParameter $param): string + private static function exportDefault(\ReflectionParameter $param, $namespace): string { $default = rtrim(substr(explode('$'.$param->name.' = ', (string) $param, 2)[1] ?? '', 0, -2)); @@ -347,7 +349,7 @@ private static function exportDefault(\ReflectionParameter $param): string $regexp = "/(\"(?:[^\"\\\\]*+(?:\\\\.)*+)*+\"|'(?:[^'\\\\]*+(?:\\\\.)*+)*+')/"; $parts = preg_split($regexp, $default, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); - $regexp = '/([\[\( ]|^)([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z0-9_\x7f-\xff]++)*+)(?!: )/'; + $regexp = '/([\[\( ]|^)([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z0-9_\x7f-\xff]++)*+)(\(?)(?!: )/'; $callback = (false !== strpbrk($default, "\\:('") && $class = $param->getDeclaringClass()) ? fn ($m) => $m[1].match ($m[2]) { 'new', 'false', 'true', 'null' => $m[2], @@ -355,13 +357,13 @@ private static function exportDefault(\ReflectionParameter $param): string 'self' => '\\'.$class->name, 'namespace\\parent', 'parent' => ($parent = $class->getParentClass()) ? '\\'.$parent->name : 'parent', - default => '\\'.$m[2], - } + default => self::exportSymbol($m[2], '(' !== $m[3], $namespace), + }.$m[3] : fn ($m) => $m[1].match ($m[2]) { 'new', 'false', 'true', 'null', 'self', 'parent' => $m[2], 'NULL' => 'null', - default => '\\'.$m[2], - }; + default => self::exportSymbol($m[2], '(' !== $m[3], $namespace), + }.$m[3]; return implode('', array_map(fn ($part) => match ($part[0]) { '"' => $part, // for internal classes only @@ -369,4 +371,18 @@ private static function exportDefault(\ReflectionParameter $param): string default => preg_replace_callback($regexp, $callback, $part), }, $parts)); } + + private static function exportSymbol(string $symbol, bool $mightBeRootConst, string $namespace): string + { + if (!$mightBeRootConst + || false === ($ns = strrpos($symbol, '\\')) + || substr($symbol, 0, $ns) !== $namespace + || \defined($symbol) + || !\defined(substr($symbol, $ns + 1)) + ) { + return '\\'.$symbol; + } + + return '\\'.substr($symbol, $ns + 1); + } } diff --git a/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php b/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php index c10f47d495d82..6cc0dd7d8c498 100644 --- a/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php +++ b/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php @@ -37,6 +37,7 @@ public static function provideExportSignature() $expected = str_replace(['.', ' . . . ', '\'$a\', \'$a\n\', "\$a\n"'], [' . ', '...', '\'$a\', "\$a\\\n", "\$a\n"'], $expected); $expected = str_replace('Bar', '\\'.Bar::class, $expected); $expected = str_replace('self', '\\'.TestForProxyHelper::class, $expected); + $expected = str_replace('= [namespace\\M_PI, new M_PI]', '= [\M_PI, new \Symfony\Component\VarExporter\Tests\M_PI()]', $expected); yield [$expected, $method]; } @@ -237,6 +238,10 @@ public static function foo8() public function foo9($a = self::BOB, $b = ['$a', '$a\n', "\$a\n"], $c = ['$a', '$a\n', "\$a\n", new \stdClass()]) { } + + public function foo10($a = [namespace\M_PI, new M_PI()]) + { + } } interface TestForProxyHelperInterface1