From f5c9f8bcd3887f42a5d4d5bbb5dac67ef888c950 Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Thu, 13 Feb 2025 23:30:28 -0800 Subject: [PATCH 01/11] gen_stub: fix `PropertyInfo::getString()` version compatibility (#17779) I forgot a `$this->` in #15751 --- build/gen_stub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 4205360d9a64f..be524edd5d425 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3071,7 +3071,7 @@ private function getString(string $propName): array { ]; // If not set, use the current latest version $allVersions = ALL_PHP_VERSION_IDS; - $minPhp = $phpVersionIdMinimumCompatibility ?? end($allVersions); + $minPhp = $this->phpVersionIdMinimumCompatibility ?? end($allVersions); if ($minPhp < PHP_80_VERSION_ID) { // No known strings in 7.0 return $result; From 12c89aa853155e91df49b2b484ef4df2c33e9851 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 10:03:56 -0800 Subject: [PATCH 02/11] gen_stub: merge `ConstOrClassConstName` interface into `AbstractConstName` Interface is only directly implemented by the abstract class, no need to have a separate interface. --- build/gen_stub.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index be524edd5d425..d1cc441db7f53 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -861,19 +861,15 @@ public function __toString(): string; public function getDeclarationName(): string; } -interface ConstOrClassConstName extends VariableLikeName { - public function equals(ConstOrClassConstName $const): bool; - public function isClassConst(): bool; - public function isUnknown(): bool; -} - -abstract class AbstractConstName implements ConstOrClassConstName +abstract class AbstractConstName implements VariableLikeName { - public function equals(ConstOrClassConstName $const): bool + public function equals(AbstractConstName $const): bool { return $this->__toString() === $const->__toString(); } + abstract public function isClassConst(): bool; + public function isUnknown(): bool { return strtolower($this->__toString()) === "unknown"; @@ -2468,7 +2464,7 @@ protected function addFlagForVersionsAbove(array $flags, string $flag, int $mini class ConstInfo extends VariableLike { - public /* readonly */ ConstOrClassConstName $name; + public /* readonly */ AbstractConstName $name; public /* readonly */ Expr $value; public bool $isDeprecated; public ?string $valueString; @@ -2481,7 +2477,7 @@ class ConstInfo extends VariableLike * @var AttributeInfo[] $attributes */ public function __construct( - ConstOrClassConstName $name, + AbstractConstName $name, int $flags, Expr $value, ?string $valueString, @@ -4455,7 +4451,7 @@ function parseFunctionLike( */ function parseConstLike( PrettyPrinterAbstract $prettyPrinter, - ConstOrClassConstName $name, + AbstractConstName $name, Node\Const_ $const, int $flags, ?Node $type, From 97cd9fdc137ebcc50b8676f135016898856414a6 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 10:43:16 -0800 Subject: [PATCH 03/11] gen_stub: combine identical condition blocks --- build/gen_stub.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index d1cc441db7f53..10e2e65b88513 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1426,9 +1426,7 @@ public function getFunctionEntry(): string { if (!$php84MinimumCompatibility) { $code .= "#else\n"; - } - if (!$php84MinimumCompatibility) { $flags = array_slice($flagsByPhpVersions, 0, 4, true); $template = "\tZEND_RAW_FENTRY($zendName, $name, $argInfoName, %s)\n"; $flagsCode = generateVersionDependentFlagCode( @@ -1437,9 +1435,7 @@ public function getFunctionEntry(): string { $this->minimumPhpVersionIdCompatibility ); $code .= implode("", $flagsCode); - } - if (!$php84MinimumCompatibility) { $code .= "#endif\n"; } } From eafddfd3d91ff7f741947814a3a0db2850db7808 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 10:56:42 -0800 Subject: [PATCH 04/11] gen_stub: document more readonly class properties --- build/gen_stub.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 10e2e65b88513..916ae9cc32aa4 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2463,11 +2463,11 @@ class ConstInfo extends VariableLike public /* readonly */ AbstractConstName $name; public /* readonly */ Expr $value; public bool $isDeprecated; - public ?string $valueString; + public /* readonly */ ?string $valueString; public /* readonly */ ?string $cond; - public ?string $cValue; - public bool $isUndocumentable; - public bool $isFileCacheAllowed; + public /* readonly */ ?string $cValue; + public /* readonly */ bool $isUndocumentable; + public /* readonly */ bool $isFileCacheAllowed; /** * @var AttributeInfo[] $attributes @@ -3262,7 +3262,7 @@ class ClassInfo { public /* readonly */ array $enumCaseInfos; public /* readonly */ ?string $cond; public ?int $phpVersionIdMinimumCompatibility; - public bool $isUndocumentable; + public /* readonly */ bool $isUndocumentable; /** * @param AttributeInfo[] $attributes From 9da6050e0865a26746d3e17f26e971ae24a61a16 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 10:58:29 -0800 Subject: [PATCH 05/11] gen_stub: add visibility to class constants Make everything public for now --- build/gen_stub.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 916ae9cc32aa4..f3cac6d268394 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -772,9 +772,9 @@ public function toTypeMask(): string { } class ArgInfo { - const SEND_BY_VAL = "0"; - const SEND_BY_REF = "1"; - const SEND_PREFER_REF = "ZEND_SEND_PREFER_REF"; + public const SEND_BY_VAL = "0"; + public const SEND_BY_REF = "1"; + public const SEND_PREFER_REF = "ZEND_SEND_PREFER_REF"; public /* readonly */ string $name; public /* readonly */ string $sendBy; @@ -1088,11 +1088,11 @@ public function isDestructor(): bool { } class ReturnInfo { - const REFCOUNT_0 = "0"; - const REFCOUNT_1 = "1"; - const REFCOUNT_N = "N"; + public const REFCOUNT_0 = "0"; + public const REFCOUNT_1 = "1"; + public const REFCOUNT_N = "N"; - const REFCOUNTS_NONSCALAR = [ + public const REFCOUNTS_NONSCALAR = [ self::REFCOUNT_1, self::REFCOUNT_N, ]; From 4af64fdbfa32ced473ca10043b46a71faf2805fe Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 11:02:31 -0800 Subject: [PATCH 06/11] gen_stub: convert `parseFramelessFunctionInfo()` to a constructor Also mark `FramelessFunctionInfo::$arity` readonly --- build/gen_stub.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index f3cac6d268394..4f114136566df 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -4238,15 +4238,14 @@ function parseDocComment(DocComment $comment): array { } class FramelessFunctionInfo { - public int $arity; -} + public /* readonly */ int $arity; + + public function __construct(string $json) { + // FIXME: Should have some validation + $json = json_decode($json, true); -function parseFramelessFunctionInfo(string $json): FramelessFunctionInfo { - // FIXME: Should have some validation - $json = json_decode($json, true); - $framelessFunctionInfo = new FramelessFunctionInfo(); - $framelessFunctionInfo->arity = $json["arity"]; - return $framelessFunctionInfo; + $this->arity = $json["arity"]; + } } function parseFunctionLike( @@ -4330,7 +4329,7 @@ function parseFunctionLike( break; case 'frameless-function': - $framelessFunctionInfos[] = parseFramelessFunctionInfo($tag->getValue()); + $framelessFunctionInfos[] = new FramelessFunctionInfo($tag->getValue()); break; } } From c2f81073fd114476bf112282b63e8c816b150037 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 11:20:04 -0800 Subject: [PATCH 07/11] gen_stub: clean up some variable declarations Inline single-use variables, remove unneeded forward declarations --- build/gen_stub.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 4f114136566df..32cb6e041986e 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -4599,14 +4599,12 @@ function parseClass( ?int $minimumPhpVersionIdCompatibility, bool $isUndocumentable ): ClassInfo { - $flags = $class instanceof Class_ ? $class->flags : 0; $comments = $class->getComments(); $alias = null; $isDeprecated = false; $isStrictProperties = false; $isNotSerializable = false; $allowsDynamicProperties = false; - $attributes = []; if ($comments) { $tags = parseDocComments($comments); @@ -4667,7 +4665,7 @@ function parseClass( return new ClassInfo( $name, - $flags, + $class instanceof Class_ ? $class->flags : 0, $classKind, $alias, $class instanceof Enum_ && $class->scalarType !== null @@ -4911,8 +4909,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac } function parseStubFile(string $code): FileInfo { - $lexer = new PhpParser\Lexer\Emulative(); - $parser = new PhpParser\Parser\Php7($lexer); + $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative()); $nodeTraverser = new PhpParser\NodeTraverser; $nodeTraverser->addVisitor(new PhpParser\NodeVisitor\NameResolver); $prettyPrinter = new class extends Standard { @@ -5178,8 +5175,7 @@ static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) { $framelessFunctionCode = generateCodeWithConditions( $fileInfo->getAllFuncInfos(), "\n", static function (FuncInfo $funcInfo) { - $code = $funcInfo->getFramelessDeclaration($funcInfo); - return $code; + return $funcInfo->getFramelessDeclaration($funcInfo); } ); From 6b741e34d0ad7274e0c06c0ce4cda6dc8aa630a5 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 11:26:04 -0800 Subject: [PATCH 08/11] gen_stub: whitespace and readability improvements Remove blank lines at the start of functions, ensure there are spaces between parameters, split a long function call across multiple lines --- build/gen_stub.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 32cb6e041986e..13bd6812c8f1e 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3087,7 +3087,7 @@ private function getString(string $propName): array { $include = array_merge($include, self::PHP_81_KNOWN); break; } - if (array_key_exists($propName,$include)) { + if (array_key_exists($propName, $include)) { $knownStr = $include[$propName]; return [ '', @@ -3584,7 +3584,6 @@ public function discardInfoForOldPhpVersions(?int $phpVersionIdMinimumCompatibil * @param iterable $allConstInfo */ public function getClassSynopsisDocument(array $classMap, array $allConstInfos): ?string { - $doc = new DOMDocument(); $doc->formatOutput = true; $classSynopsis = $this->getClassSynopsisElement($doc, $classMap, $allConstInfos); @@ -3602,7 +3601,6 @@ public function getClassSynopsisDocument(array $classMap, array $allConstInfos): * @param array $allConstInfos */ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, array $allConstInfos): ?DOMElement { - $classSynopsis = $doc->createElement("classsynopsis"); $classSynopsis->setAttribute("class", $this->type === "interface" ? "interface" : "class"); @@ -4888,7 +4886,15 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac } $fileInfo->classInfos[] = parseClass( - $className, $stmt, $constInfos, $propertyInfos, $methodInfos, $enumCaseInfos, $cond, $fileInfo->getMinimumPhpVersionIdCompatibility(), $fileInfo->isUndocumentable + $className, + $stmt, + $constInfos, + $propertyInfos, + $methodInfos, + $enumCaseInfos, + $cond, + $fileInfo->getMinimumPhpVersionIdCompatibility(), + $fileInfo->isUndocumentable ); continue; } @@ -5034,7 +5040,7 @@ function funcInfoToCode(FileInfo $fileInfo, FuncInfo $funcInfo): string { } else { $code .= sprintf( "\tZEND_%s_OBJ_INFO%s(%s, %s, %s, %d%s)\n", - $argKind,$argDefaultKind, $argInfo->sendBy, $argInfo->name, + $argKind, $argDefaultKind, $argInfo->sendBy, $argInfo->name, $simpleArgType->toEscapedName(), $argType->isNullable(), $argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : "" ); @@ -5376,7 +5382,6 @@ function generatePropertyAttributeInitialization( /** @param array $funcMap */ function generateOptimizerInfo(array $funcMap): string { - $code = "/* This is a generated file, edit the .stub.php files instead. */\n\n"; $code .= "static const func_info_t func_infos[] = {\n"; From d8e8ce0e2a858d63a8b1f9196aeb82ccde16d8a3 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 11:30:03 -0800 Subject: [PATCH 09/11] gen_stub: stop cloning `AttributeInfo` objects They are immutable --- build/gen_stub.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 13bd6812c8f1e..27fb26ed47167 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2085,9 +2085,6 @@ public function __clone() $this->args[$key] = clone $argInfo; } $this->return = clone $this->return; - foreach ($this->attributes as $key => $attribute) { - $this->attributes[$key] = clone $attribute; - } foreach ($this->framelessFunctionInfos as $key => $framelessFunctionInfo) { $this->framelessFunctionInfos[$key] = clone $framelessFunctionInfo; } @@ -3151,9 +3148,6 @@ public function __clone() if ($this->type) { $this->type = clone $this->type; } - foreach ($this->attributes as $key => $attribute) { - $this->attributes[$key] = clone $attribute; - } } } @@ -3183,6 +3177,8 @@ public function getDeclaration(array $allConstInfos): string { } } +// Instances of AttributeInfo are immutable and do not need to be cloned +// when held by an object that is cloned class AttributeInfo { public /* readonly */ string $class; /** @var \PhpParser\Node\Arg[] */ @@ -4012,10 +4008,6 @@ public function __clone() foreach ($this->funcInfos as $key => $funcInfo) { $this->funcInfos[$key] = clone $funcInfo; } - - foreach ($this->attributes as $key => $attribute) { - $this->attributes[$key] = clone $attribute; - } } /** From 367c5b522a43403a77872c40f6b3c6c71743f2f3 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Tue, 4 Feb 2025 11:32:15 -0800 Subject: [PATCH 10/11] gen_stub: stop cloning `FramelessFunctionInfo` objects They are immutable --- build/gen_stub.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 27fb26ed47167..f060cc1cebae0 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2085,9 +2085,6 @@ public function __clone() $this->args[$key] = clone $argInfo; } $this->return = clone $this->return; - foreach ($this->framelessFunctionInfos as $key => $framelessFunctionInfo) { - $this->framelessFunctionInfos[$key] = clone $framelessFunctionInfo; - } } } @@ -4227,6 +4224,8 @@ function parseDocComment(DocComment $comment): array { return $tags; } +// Instances of FramelessFunctionInfo are immutable and do not need to be cloned +// when held by an object that is cloned class FramelessFunctionInfo { public /* readonly */ int $arity; From 77d5eb6a5a706c84d7dea0e55c4e539f1e9e03cc Mon Sep 17 00:00:00 2001 From: David Hein <44842054+MasterZydra@users.noreply.github.com> Date: Fri, 14 Feb 2025 12:03:53 +0100 Subject: [PATCH 11/11] [skip ci] Fix tests with multiline titles (GH-17763) See GH-17761 --- tests/classes/unset_properties.phpt | 3 +-- tests/lang/foreachLoop.010.phpt | 1 + tests/lang/func_get_arg.005.phpt | 1 + tests/output/stream_isatty_no_warning_on_cast.phpt | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/classes/unset_properties.phpt b/tests/classes/unset_properties.phpt index fa576713d595d..87b3830efdcd5 100644 --- a/tests/classes/unset_properties.phpt +++ b/tests/classes/unset_properties.phpt @@ -1,6 +1,5 @@ --TEST-- -Un-setting instance properties causes magic methods to be called when trying to access them from outside the magic -methods themselves. +Un-setting instance properties causes magic methods to be called when trying to access them from outside the magic methods themselves. --FILE--