From 78d7805b4323ecb9c0bd6486d3b0da9233653117 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 17:16:07 -0800 Subject: [PATCH 01/10] gen_stub: reduce the number of public properties The following properties are made private: * `ArrayType::$keyType`, `::$valueType` * `ArginfoType::$builtinTypes` * `ConstName::$const` * `ClassConstName::$const` * `PropertyName::$property` * `FuncInfo::$classFlags`, `::$isDeprecated`, `::$supportsCompileTimeEval`, `::$minimumPhpVersionIdCompatibility`, `::$framelessFunctionInfos`, `::$exposedDocComment` * `VariableLike::$link` * `ConstInfo::$isDeprecated`, `::$valueString`, `::$isFileCacheAllowed` * `PropertyInfo::$classFlags`, `::$defaultValue`, `::$defaultValueString`, `::$isDocReadonly`, `::$isVirtual` * `EnumCaseInfo::$name`, `::$value` * `AttributeInfo::$args` * `ClassInfo::$enumBackingType`, `::$isDeprecated`, `::$exposedDocComment`, `::$isStrictProperties`, `::$isNotSerializable`, `::$propertyInfos`, `::$enumCaseInfos` The following are made protected: * `VariableLike::$exposedDocComment`, `::$phpVersionIdMinimumCompatibility` --- build/gen_stub.php | 64 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index f060cc1cebae0..1734c67744492 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -185,8 +185,8 @@ class Context { } class ArrayType extends SimpleType { - public /* readonly */ Type $keyType; - public /* readonly */ Type $valueType; + private /* readonly */ Type $keyType; + private /* readonly */ Type $valueType; public static function createGenericArray(): self { @@ -877,7 +877,7 @@ public function isUnknown(): bool } class ConstName extends AbstractConstName { - public /* readonly */ string $const; + private /* readonly */ string $const; public function __construct(?Name $namespace, string $const) { @@ -914,7 +914,7 @@ public function getDeclarationName(): string class ClassConstName extends AbstractConstName { public /* readonly */ Name $class; - public /* readonly */ string $const; + private /* readonly */ string $const; public function __construct(Name $class, string $const) { @@ -940,7 +940,7 @@ public function getDeclarationName(): string class PropertyName implements VariableLikeName { public /* readonly */ Name $class; - public /* readonly */ string $property; + private /* readonly */ string $property; public function __construct(Name $class, string $property) { @@ -1148,12 +1148,12 @@ private function setRefcount(?string $refcount): void class FuncInfo { public /* readonly */ FunctionOrMethodName $name; - public /* readonly */ int $classFlags; + private /* readonly */ int $classFlags; public int $flags; public /* readonly */ ?string $aliasType; public ?FunctionOrMethodName $alias; - public /* readonly */ bool $isDeprecated; - public bool $supportsCompileTimeEval; + private /* readonly */ bool $isDeprecated; + private bool $supportsCompileTimeEval; public /* readonly */ bool $verify; /** @var ArgInfo[] */ public /* readonly */ array $args; @@ -1161,12 +1161,12 @@ class FuncInfo { public /* readonly */ int $numRequiredArgs; public /* readonly */ ?string $cond; public bool $isUndocumentable; - public ?int $minimumPhpVersionIdCompatibility; + private ?int $minimumPhpVersionIdCompatibility; /** @var AttributeInfo[] */ public array $attributes; /** @var FramelessFunctionInfo[] */ - public array $framelessFunctionInfos; - public ?ExposedDocComment $exposedDocComment; + private array $framelessFunctionInfos; + private ?ExposedDocComment $exposedDocComment; /** * @param ArgInfo[] $args @@ -2274,11 +2274,11 @@ abstract class VariableLike public int $flags; public ?Type $type; public /* readonly */ ?Type $phpDocType; - public /* readonly */ ?string $link; - public ?int $phpVersionIdMinimumCompatibility; + private /* readonly */ ?string $link; + protected ?int $phpVersionIdMinimumCompatibility; /** @var AttributeInfo[] */ public array $attributes; - public /* readonly */ ?ExposedDocComment $exposedDocComment; + protected /* readonly */ ?ExposedDocComment $exposedDocComment; /** * @var AttributeInfo[] $attributes @@ -2456,12 +2456,12 @@ class ConstInfo extends VariableLike { public /* readonly */ AbstractConstName $name; public /* readonly */ Expr $value; - public bool $isDeprecated; - public /* readonly */ ?string $valueString; + private bool $isDeprecated; + private /* readonly */ ?string $valueString; public /* readonly */ ?string $cond; public /* readonly */ ?string $cValue; public /* readonly */ bool $isUndocumentable; - public /* readonly */ bool $isFileCacheAllowed; + private /* readonly */ bool $isFileCacheAllowed; /** * @var AttributeInfo[] $attributes @@ -2814,12 +2814,12 @@ protected function addModifiersToFieldSynopsis(DOMDocument $doc, DOMElement $fie class PropertyInfo extends VariableLike { - public /* readonly */ int $classFlags; + private /* readonly */ int $classFlags; public /* readonly */ PropertyName $name; - public /* readonly */ ?Expr $defaultValue; - public /* readonly */ ?string $defaultValueString; - public /* readonly */ bool $isDocReadonly; - public /* readonly */ bool $isVirtual; + private /* readonly */ ?Expr $defaultValue; + private /* readonly */ ?string $defaultValueString; + private /* readonly */ bool $isDocReadonly; + private /* readonly */ bool $isVirtual; // Map possible variable names to the known string constant, see // ZEND_KNOWN_STRINGS @@ -3149,8 +3149,8 @@ public function __clone() } class EnumCaseInfo { - public /* readonly */ string $name; - public /* readonly */ ?Expr $value; + private /* readonly */ string $name; + private /* readonly */ ?Expr $value; public function __construct(string $name, ?Expr $value) { $this->name = $name; @@ -3179,7 +3179,7 @@ public function getDeclaration(array $allConstInfos): string { class AttributeInfo { public /* readonly */ string $class; /** @var \PhpParser\Node\Arg[] */ - public /* readonly */ array $args; + private /* readonly */ array $args; /** @param \PhpParser\Node\Arg[] $args */ public function __construct(string $class, array $args) { @@ -3234,13 +3234,13 @@ class ClassInfo { public int $flags; public string $type; public /* readonly */ ?string $alias; - public /* readonly */ ?SimpleType $enumBackingType; - public /* readonly */ bool $isDeprecated; - public bool $isStrictProperties; + private /* readonly */ ?SimpleType $enumBackingType; + private /* readonly */ bool $isDeprecated; + private bool $isStrictProperties; /** @var AttributeInfo[] */ public array $attributes; - public ?ExposedDocComment $exposedDocComment; - public bool $isNotSerializable; + private ?ExposedDocComment $exposedDocComment; + private bool $isNotSerializable; /** @var Name[] */ public /* readonly */ array $extends; /** @var Name[] */ @@ -3248,11 +3248,11 @@ class ClassInfo { /** @var ConstInfo[] */ public /* readonly */ array $constInfos; /** @var PropertyInfo[] */ - public /* readonly */ array $propertyInfos; + private /* readonly */ array $propertyInfos; /** @var FuncInfo[] */ public array $funcInfos; /** @var EnumCaseInfo[] */ - public /* readonly */ array $enumCaseInfos; + private /* readonly */ array $enumCaseInfos; public /* readonly */ ?string $cond; public ?int $phpVersionIdMinimumCompatibility; public /* readonly */ bool $isUndocumentable; From 4ad5c5efec5d998bef044589164afc1b88564197 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 17:27:21 -0800 Subject: [PATCH 02/10] gen_stub: add `FileInfo` constructor Move the logic from `parseStubFile()` to `FileInfo::__construct()`, and in the process inline and remove `FileInfo::setMinimumPhpVersionIdCompatibility()`. --- build/gen_stub.php | 66 ++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 1734c67744492..1329e40938ad0 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -4050,6 +4050,35 @@ class FileInfo { public bool $legacyArginfoGeneration = false; private ?int $minimumPhpVersionIdCompatibility = null; + public function __construct(array $fileTags) { + foreach ($fileTags as $tag) { + if ($tag->name === 'generate-function-entries') { + $this->generateFunctionEntries = true; + $this->declarationPrefix = $tag->value ? $tag->value . " " : ""; + } else if ($tag->name === 'generate-legacy-arginfo') { + if ($tag->value && !in_array((int) $tag->value, ALL_PHP_VERSION_IDS, true)) { + throw new Exception( + "Legacy PHP version must be one of: \"" . PHP_70_VERSION_ID . "\" (PHP 7.0), \"" . PHP_80_VERSION_ID . "\" (PHP 8.0), " . + "\"" . PHP_81_VERSION_ID . "\" (PHP 8.1), \"" . PHP_82_VERSION_ID . "\" (PHP 8.2), \"" . PHP_83_VERSION_ID . "\" (PHP 8.3), " . + "\"" . PHP_84_VERSION_ID . "\" (PHP 8.4), \"" . PHP_85_VERSION_ID . "\" (PHP 8.5), \"" . $tag->value . "\" provided" + ); + } + + $this->minimumPhpVersionIdCompatibility = ($tag->value ? (int) $tag->value : PHP_70_VERSION_ID); + } else if ($tag->name === 'generate-class-entries') { + $this->generateClassEntries = true; + $this->declarationPrefix = $tag->value ? $tag->value . " " : ""; + } else if ($tag->name === 'undocumentable') { + $this->isUndocumentable = true; + } + } + + // Generating class entries require generating function/method entries + if ($this->generateClassEntries && !$this->generateFunctionEntries) { + $this->generateFunctionEntries = true; + } + } + /** * @return iterable */ @@ -4101,10 +4130,6 @@ public function __clone() } } - public function setMinimumPhpVersionIdCompatibility(?int $minimumPhpVersionIdCompatibility) { - $this->minimumPhpVersionIdCompatibility = $minimumPhpVersionIdCompatibility; - } - public function getMinimumPhpVersionIdCompatibility(): ?int { // Non-legacy arginfo files are always PHP 8.0+ compatible if (!$this->legacyArginfoGeneration && @@ -4918,37 +4943,8 @@ protected function pName_FullyQualified(Name\FullyQualified $node): string { $stmts = $parser->parse($code); $nodeTraverser->traverse($stmts); - $fileInfo = new FileInfo; - $fileDocComments = getFileDocComments($stmts); - if ($fileDocComments !== []) { - $fileTags = parseDocComments($fileDocComments); - foreach ($fileTags as $tag) { - if ($tag->name === 'generate-function-entries') { - $fileInfo->generateFunctionEntries = true; - $fileInfo->declarationPrefix = $tag->value ? $tag->value . " " : ""; - } else if ($tag->name === 'generate-legacy-arginfo') { - if ($tag->value && !in_array((int) $tag->value, ALL_PHP_VERSION_IDS, true)) { - throw new Exception( - "Legacy PHP version must be one of: \"" . PHP_70_VERSION_ID . "\" (PHP 7.0), \"" . PHP_80_VERSION_ID . "\" (PHP 8.0), " . - "\"" . PHP_81_VERSION_ID . "\" (PHP 8.1), \"" . PHP_82_VERSION_ID . "\" (PHP 8.2), \"" . PHP_83_VERSION_ID . "\" (PHP 8.3), " . - "\"" . PHP_84_VERSION_ID . "\" (PHP 8.4), \"" . PHP_85_VERSION_ID . "\" (PHP 8.5), \"" . $tag->value . "\" provided" - ); - } - - $fileInfo->setMinimumPhpVersionIdCompatibility($tag->value ? (int) $tag->value : PHP_70_VERSION_ID); - } else if ($tag->name === 'generate-class-entries') { - $fileInfo->generateClassEntries = true; - $fileInfo->declarationPrefix = $tag->value ? $tag->value . " " : ""; - } else if ($tag->name === 'undocumentable') { - $fileInfo->isUndocumentable = true; - } - } - } - - // Generating class entries require generating function/method entries - if ($fileInfo->generateClassEntries && !$fileInfo->generateFunctionEntries) { - $fileInfo->generateFunctionEntries = true; - } + $fileTags = parseDocComments(getFileDocComments($stmts)); + $fileInfo = new FileInfo($fileTags); handleStatements($fileInfo, $stmts, $prettyPrinter); return $fileInfo; From 204203a86220db791cc13a5cafcdee2349d2ae55 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 17:30:00 -0800 Subject: [PATCH 03/10] gen_stub: remove `FuncInfo::getFramelessDeclaration()` parameter Unused, only caller passes in the same FuncInfo object that the method is called on. --- build/gen_stub.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 1329e40938ad0..05f6ed4f0bb03 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1308,7 +1308,7 @@ public function getDeclaration(): ?string return $name->getDeclaration(); } - public function getFramelessDeclaration(FuncInfo $funcInfo): ?string { + public function getFramelessDeclaration(): ?string { if (empty($this->framelessFunctionInfos)) { return null; } @@ -5168,7 +5168,7 @@ static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) { $framelessFunctionCode = generateCodeWithConditions( $fileInfo->getAllFuncInfos(), "\n", static function (FuncInfo $funcInfo) { - return $funcInfo->getFramelessDeclaration($funcInfo); + return $funcInfo->getFramelessDeclaration(); } ); From de5429cce167e9c1825296728733a2b4996ce610 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 17:33:31 -0800 Subject: [PATCH 04/10] gen_stub: add `report_file_put_contents()` helper Deduplicate reporting out each time a file is saved --- build/gen_stub.php | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 05f6ed4f0bb03..eaef00cb2b8c7 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -36,6 +36,13 @@ PHP_85_VERSION_ID, ]; +// file_put_contents() but with a success message printed after saving +function report_file_put_contents(string $filename, string $content) { + if (file_put_contents($filename, $content)) { + echo "Saved $filename\n"; + } +} + /** * @return FileInfo[] */ @@ -121,8 +128,8 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly = $context->allConstInfos, $stubHash ); - if (($context->forceRegeneration || $stubHash !== $oldStubHash) && file_put_contents($arginfoFile, $arginfoCode)) { - echo "Saved $arginfoFile\n"; + if ($context->forceRegeneration || $stubHash !== $oldStubHash) { + report_file_put_contents($arginfoFile, $arginfoCode); } if ($fileInfo->shouldGenerateLegacyArginfo()) { @@ -146,8 +153,8 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly = $context->allConstInfos, $stubHash ); - if (($context->forceRegeneration || $stubHash !== $oldStubHash) && file_put_contents($legacyFile, $arginfoCode)) { - echo "Saved $legacyFile\n"; + if ($context->forceRegeneration || $stubHash !== $oldStubHash) { + report_file_put_contents($legacyFile, $arginfoCode); } } @@ -6289,9 +6296,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc if ($replacePredefinedConstants) { foreach ($predefinedConstants as $filename => $content) { - if (file_put_contents($filename, $content)) { - echo "Saved $filename\n"; - } + report_file_put_contents($filename, $content); } } } @@ -6306,9 +6311,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc } foreach ($classSynopses as $filename => $content) { - if (file_put_contents("$classSynopsesDirectory/$filename", $content)) { - echo "Saved $filename\n"; - } + report_file_put_contents("$classSynopsesDirectory/$filename", $content); } } } @@ -6318,9 +6321,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc if ($replaceClassSynopses) { foreach ($classSynopses as $filename => $content) { - if (file_put_contents($filename, $content)) { - echo "Saved $filename\n"; - } + report_file_put_contents($filename, $content); } } } @@ -6339,9 +6340,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc mkdir(dirname($path)); } - if (file_put_contents($path, $content)) { - echo "Saved $filename\n"; - } + report_file_put_contents($path, $content); } } } @@ -6351,9 +6350,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc if ($replaceMethodSynopses) { foreach ($methodSynopses as $filename => $content) { - if (file_put_contents($filename, $content)) { - echo "Saved $filename\n"; - } + report_file_put_contents($filename, $content); } } } @@ -6362,9 +6359,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc $filename = dirname(__FILE__, 2) . "/Zend/Optimizer/zend_func_infos.h"; $optimizerInfo = generateOptimizerInfo($funcMap); - if (file_put_contents($filename, $optimizerInfo)) { - echo "Saved $filename\n"; - } + report_file_put_contents($filename, $optimizerInfo); } if ($verifyManual) { From eab0886357be3b285bc5ec45f11f94c2255770d2 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 17:36:39 -0800 Subject: [PATCH 05/10] gen_stub: stop cloning `Type` objects They are immutable --- build/gen_stub.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index eaef00cb2b8c7..029a19ad0c31a 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -531,6 +531,8 @@ public function equals(SimpleType $other): bool { } } +// Instances of Type are immutable and do not need to be cloned +// when held by an object that is cloned class Type { /** @var SimpleType[] */ public /* readonly */ array $types; @@ -3146,13 +3148,6 @@ protected function addModifiersToFieldSynopsis(DOMDocument $doc, DOMElement $fie $fieldsynopsisElement->appendChild($doc->createElement("modifier", "readonly")); } } - - public function __clone() - { - if ($this->type) { - $this->type = clone $this->type; - } - } } class EnumCaseInfo { From 8afc7dd3ddcd0c335409e5bf5d6dfd9a51623653 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 17:49:12 -0800 Subject: [PATCH 06/10] gen_stub: move `createExposedDocComment()` into `ExposedDocComment` Reduce the number of global functions by moving it to `ExposedDocComment::extractExposedComment()` --- build/gen_stub.php | 54 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 029a19ad0c31a..64131303ddb0e 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -4223,6 +4223,29 @@ public function escape(): string { public function getLength(): int { return strlen($this->docComment); } + + /** @param array $comments */ + public static function extractExposedComment(array $comments): ?ExposedDocComment { + $exposedDocComment = null; + + foreach ($comments as $comment) { + $text = $comment->getText(); + $matches = []; + $pattern = "#^(\s*\/\*\*)(\s*@genstubs-expose-comment-block)(\s*)$#m"; + + if (preg_match($pattern, $text, $matches) !== 1) { + continue; + } + + if ($exposedDocComment !== null) { + throw new Exception("Only one PHPDoc comment block can be exposed"); + } + + $exposedDocComment = preg_replace($pattern, '$1$3', $text); + } + + return $exposedDocComment ? new ExposedDocComment($exposedDocComment) : null; + } } /** @return DocCommentTag[] */ @@ -4450,7 +4473,7 @@ function parseFunctionLike( $minimumPhpVersionIdCompatibility, createAttributes($func->attrGroups), $framelessFunctionInfos, - createExposedDocComment($comments) + ExposedDocComment::extractExposedComment($comments) ); } catch (Exception $e) { throw new Exception($name . "(): " .$e->getMessage()); @@ -4527,7 +4550,7 @@ function parseConstLike( $link, $phpVersionIdMinimumCompatibility, $attributes, - createExposedDocComment($comments), + ExposedDocComment::extractExposedComment($comments), $isFileCacheAllowed ); } @@ -4594,7 +4617,7 @@ function parseProperty( $link, $phpVersionIdMinimumCompatibility, $attributes, - createExposedDocComment($comments) + ExposedDocComment::extractExposedComment($comments) ); } @@ -4689,7 +4712,7 @@ function parseClass( $isDeprecated, $isStrictProperties, $attributes, - createExposedDocComment($comments), + ExposedDocComment::extractExposedComment($comments), $isNotSerializable, $extends, $implements, @@ -4719,29 +4742,6 @@ function createAttributes(array $attributeGroups): array { return $attributes; } -/** @param array $comments */ -function createExposedDocComment(array $comments): ?ExposedDocComment { - $exposedDocComment = null; - - foreach ($comments as $comment) { - $text = $comment->getText(); - $matches = []; - $pattern = "#^(\s*\/\*\*)(\s*@genstubs-expose-comment-block)(\s*)$#m"; - - if (preg_match($pattern, $text, $matches) !== 1) { - continue; - } - - if ($exposedDocComment !== null) { - throw new Exception("Only one PHPDoc comment block can be exposed"); - } - - $exposedDocComment = preg_replace($pattern, '$1$3', $text); - } - - return $exposedDocComment ? new ExposedDocComment($exposedDocComment) : null; -} - function handlePreprocessorConditions(array &$conds, Stmt $stmt): ?string { foreach ($stmt->getComments() as $comment) { $text = trim($comment->getText()); From 61ecc3a2ac8892ff37df8dcc88f91f073919e264 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 17:56:17 -0800 Subject: [PATCH 07/10] gen_stub: merge `parseDocComment()` into `parseDocComments()` Reduce the number of global functions merging `parseDocComment()` into its only caller --- build/gen_stub.php | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 64131303ddb0e..0fe7150534c79 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -4252,22 +4252,15 @@ public static function extractExposedComment(array $comments): ?ExposedDocCommen function parseDocComments(array $comments): array { $tags = []; foreach ($comments as $comment) { - if ($comment instanceof DocComment) { - $tags = array_merge($tags, parseDocComment($comment)); + if (!($comment instanceof DocComment)) { + continue; } - } - - return $tags; -} - -/** @return DocCommentTag[] */ -function parseDocComment(DocComment $comment): array { - $commentText = substr($comment->getText(), 2, -2); - $tags = []; - foreach (explode("\n", $commentText) as $commentLine) { - $regex = '/^\*\s*@([a-z-]+)(?:\s+(.+))?$/'; - if (preg_match($regex, trim($commentLine), $matches)) { - $tags[] = new DocCommentTag($matches[1], $matches[2] ?? null); + $commentText = substr($comment->getText(), 2, -2); + foreach (explode("\n", $commentText) as $commentLine) { + $regex = '/^\*\s*@([a-z-]+)(?:\s+(.+))?$/'; + if (preg_match($regex, trim($commentLine), $matches)) { + $tags[] = new DocCommentTag($matches[1], $matches[2] ?? null); + } } } From 0e474cb345b8c6ccfe5ca3f3c4d33fb496a8a270 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 18:02:21 -0800 Subject: [PATCH 08/10] gen_stub: move `createAttributes()` into `AttributeInfo` Reduce the number of global functions by moving it to `AttributeInfo::createFromGroups()`. In the process, fix the documentation for the return type, the result is an array of `AttributeInfo` objects, not `Attribute` objects. --- build/gen_stub.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 0fe7150534c79..26f9e6f8d2e9b 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3229,6 +3229,22 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC } return $code; } + + /** + * @param array> $attributeGroups + * @return AttributeInfo[] + */ + public static function createFromGroups(array $attributeGroups): array { + $attributes = []; + + foreach ($attributeGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attr) { + $attributes[] = new AttributeInfo($attr->name->toString(), $attr->args); + } + } + + return $attributes; + } } class ClassInfo { @@ -4425,7 +4441,7 @@ function parseFunctionLike( $type, isset($docParamTypes[$varName]) ? Type::fromString($docParamTypes[$varName]) : null, $param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null, - createAttributes($param->attrGroups) + AttributeInfo::createFromGroups($param->attrGroups) ); if (!$param->default && !$param->variadic) { $numRequiredArgs = $i + 1; @@ -4464,7 +4480,7 @@ function parseFunctionLike( $cond, $isUndocumentable, $minimumPhpVersionIdCompatibility, - createAttributes($func->attrGroups), + AttributeInfo::createFromGroups($func->attrGroups), $framelessFunctionInfos, ExposedDocComment::extractExposedComment($comments) ); @@ -4655,7 +4671,7 @@ function parseClass( } } - $attributes = createAttributes($class->attrGroups); + $attributes = AttributeInfo::createFromGroups($class->attrGroups); foreach ($attributes as $attribute) { switch ($attribute->class) { case 'AllowDynamicProperties': @@ -4719,22 +4735,6 @@ function parseClass( ); } -/** - * @param array> $attributeGroups - * @return Attribute[] - */ -function createAttributes(array $attributeGroups): array { - $attributes = []; - - foreach ($attributeGroups as $attrGroup) { - foreach ($attrGroup->attrs as $attr) { - $attributes[] = new AttributeInfo($attr->name->toString(), $attr->args); - } - } - - return $attributes; -} - function handlePreprocessorConditions(array &$conds, Stmt $stmt): ?string { foreach ($stmt->getComments() as $comment) { $text = trim($comment->getText()); @@ -4854,7 +4854,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac $cond, $fileInfo->isUndocumentable, $fileInfo->getMinimumPhpVersionIdCompatibility(), - createAttributes($classStmt->attrGroups) + AttributeInfo::createFromGroups($classStmt->attrGroups) ); } } else if ($classStmt instanceof Stmt\Property) { @@ -4871,7 +4871,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac $classStmt->getComments(), $prettyPrinter, $fileInfo->getMinimumPhpVersionIdCompatibility(), - createAttributes($classStmt->attrGroups) + AttributeInfo::createFromGroups($classStmt->attrGroups) ); } } else if ($classStmt instanceof Stmt\ClassMethod) { From 365a7e9d476b7aeab1d14604c3e387036ad59d37 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 18:07:11 -0800 Subject: [PATCH 09/10] gen_stub: simplify `getFileDocComments()` with `array_filter` --- build/gen_stub.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 26f9e6f8d2e9b..1ffaa59f3a3af 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -4769,16 +4769,10 @@ function getFileDocComments(array $stmts): array { return []; } - $comments = $stmts[0]->getComments(); - - $result = []; - foreach ($comments as $comment) { - if ($comment instanceof DocComment) { - $result[] = $comment; - } - } - - return $result; + return array_filter( + $stmts[0]->getComments(), + static fn ( $comment ) => $comment instanceof DocComment + ); } function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstract $prettyPrinter) { From 6a7982e4c82b49dc61fc33846dc881dc2c83d785 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 21 Feb 2025 18:17:05 -0800 Subject: [PATCH 10/10] gen_stub: move `findEquivalentFuncInfo()` into `FuncInfo` Reduce the number of global functions by moving it to instance method `FuncInfo::findEquivalent()`. --- build/gen_stub.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 1ffaa59f3a3af..8e250f7a35c81 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2088,6 +2088,16 @@ public function getMethodSynopsisElement(array $funcMap, array $aliasMap, DOMDoc return $methodSynopsis; } + /** @param FuncInfo[] $generatedFuncInfos */ + public function findEquivalent(array $generatedFuncInfos): ?FuncInfo { + foreach ($generatedFuncInfos as $generatedFuncInfo) { + if ($generatedFuncInfo->equalsApartFromNameAndRefcount($this)) { + return $generatedFuncInfo; + } + } + return null; + } + public function __clone() { foreach ($this->args as $key => $argInfo) { @@ -5052,16 +5062,6 @@ function funcInfoToCode(FileInfo $fileInfo, FuncInfo $funcInfo): string { return $code . "\n"; } -/** @param FuncInfo[] $generatedFuncInfos */ -function findEquivalentFuncInfo(array $generatedFuncInfos, FuncInfo $funcInfo): ?FuncInfo { - foreach ($generatedFuncInfos as $generatedFuncInfo) { - if ($generatedFuncInfo->equalsApartFromNameAndRefcount($funcInfo)) { - return $generatedFuncInfo; - } - } - return null; -} - /** * @template T * @param iterable $infos @@ -5135,7 +5135,7 @@ function generateArgInfoCode( $fileInfo->getAllFuncInfos(), "\n", static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) { /* If there already is an equivalent arginfo structure, only emit a #define */ - if ($generatedFuncInfo = findEquivalentFuncInfo($generatedFuncInfos, $funcInfo)) { + if ($generatedFuncInfo = $funcInfo->findEquivalent($generatedFuncInfos)) { $code = sprintf( "#define %s %s\n", $funcInfo->getArgInfoName(), $generatedFuncInfo->getArgInfoName()