diff --git a/extension.neon b/extension.neon index 427e107..c217aea 100644 --- a/extension.neon +++ b/extension.neon @@ -35,6 +35,10 @@ services: class: SzepeViktor\PHPStan\WordPress\GetPostsDynamicFunctionReturnTypeExtension tags: - phpstan.broker.dynamicFunctionReturnTypeExtension + - + class: SzepeViktor\PHPStan\WordPress\GetSitesDynamicFunctionReturnTypeExtension + tags: + - phpstan.broker.dynamicFunctionReturnTypeExtension - class: SzepeViktor\PHPStan\WordPress\GetTaxonomiesDynamicFunctionReturnTypeExtension tags: diff --git a/src/GetPostsDynamicFunctionReturnTypeExtension.php b/src/GetPostsDynamicFunctionReturnTypeExtension.php index 26ffb59..0a5b553 100644 --- a/src/GetPostsDynamicFunctionReturnTypeExtension.php +++ b/src/GetPostsDynamicFunctionReturnTypeExtension.php @@ -22,7 +22,7 @@ class GetPostsDynamicFunctionReturnTypeExtension implements \PHPStan\Type\Dynami { public function isFunctionSupported(FunctionReflection $functionReflection): bool { - return in_array($functionReflection->getName(), ['get_posts'], true); + return $functionReflection->getName() === 'get_posts'; } /** diff --git a/src/GetSitesDynamicFunctionReturnTypeExtension.php b/src/GetSitesDynamicFunctionReturnTypeExtension.php new file mode 100644 index 0000000..aa5dbfd --- /dev/null +++ b/src/GetSitesDynamicFunctionReturnTypeExtension.php @@ -0,0 +1,75 @@ +getName() === 'get_sites'; + } + + /** + * @see https://developer.wordpress.org/reference/classes/wp_query/#return-fields-parameter + */ + // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter + public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type + { + $args = $functionCall->getArgs(); + + // Called without arguments + if (count($args) === 0) { + return new ArrayType(new IntegerType(), new ObjectType('WP_Site')); + } + + $fields = ''; + + $argumentType = $scope->getType($args[0]->value); + + // Called with an array argument + if ($argumentType instanceof ConstantArrayType) { + foreach ($argumentType->getKeyTypes() as $index => $key) { + if (! $key instanceof ConstantStringType || $key->getValue() !== 'fields') { + continue; + } + + $fieldsType = $argumentType->getValueTypes()[$index]; + if ($fieldsType instanceof ConstantStringType) { + $fields = $fieldsType->getValue(); + } + break; + } + } + + // Called with a string argument + if ($argumentType instanceof ConstantStringType) { + parse_str($argumentType->getValue(), $variables); + $fields = $variables['fields'] ?? 'all'; + } + + switch ($fields) { + case 'count': + return new IntegerType(); + case 'ids': + return new ArrayType(new IntegerType(), new IntegerType()); + default: + return new ArrayType(new IntegerType(), new ObjectType('WP_Site')); + } + } +} diff --git a/tests/DynamicReturnTypeExtensionTest.php b/tests/DynamicReturnTypeExtensionTest.php index 155c9c9..c8757e9 100644 --- a/tests/DynamicReturnTypeExtensionTest.php +++ b/tests/DynamicReturnTypeExtensionTest.php @@ -20,6 +20,8 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/get_comment.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_object_taxonomies.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_post.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/get_posts.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/get_sites.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_terms.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/has_filter.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/mysql2date.php'); diff --git a/tests/data/get_posts.php b/tests/data/get_posts.php new file mode 100644 index 0000000..9de82be --- /dev/null +++ b/tests/data/get_posts.php @@ -0,0 +1,12 @@ +', get_posts()); +assertType('array', get_posts(['fields' => 'all'])); +assertType('array', get_posts(['fields' => 'ids'])); +assertType('array', get_posts(['fields' => 'id=>parent'])); diff --git a/tests/data/get_sites.php b/tests/data/get_sites.php new file mode 100644 index 0000000..fd03fd1 --- /dev/null +++ b/tests/data/get_sites.php @@ -0,0 +1,11 @@ +', get_sites()); +assertType('int', get_sites(['fields' => 'count'])); +assertType('array', get_sites(['fields' => 'ids']));