Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

functionMap: additions, improvement, corrections #127

Merged
merged 13 commits into from
Nov 2, 2023
77 changes: 40 additions & 37 deletions functionMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,37 @@
/**
* This array is in the same format as the function map array in PHPStan:
*
* '<function_name>' => ['<return_type>', '<arg_name>'=>'<arg_type>']
* '<function_name>' => ['<return_type>', '<arg_name>' => '<arg_type>']
*
* For classes, or if you don't wish to define the `@phpstan-return` tag:
*
* '<class_name>' => [null, '<arg_name>'=>'<arg_type>']
* '<class_name>' => [null, '<arg_name>' => '<arg_type>']
*
* @link https://github.com/phpstan/phpstan-src/blob/1.5.x/resources/functionMap.php
* @link https://github.com/phpstan/phpstan-src/blob/1.10.x/resources/functionMap.php
*/
return [
'addslashes_gpc' => ['T', '@phpstan-template'=>'T', 'gpc'=>'T'],
'get_objects_in_term' => [null, 'args'=>'array{order?: string}'],
'have_posts' => [null, '@phpstan-impure'=>''],
'rawurlencode_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'sanitize_category' => ['T', '@phpstan-template'=>'T of array|object', 'category'=>'T'],
'sanitize_post' => ['T', '@phpstan-template'=>'T of array|object', 'post'=>'T'],
'sanitize_term' => ['T', '@phpstan-template'=>'T of array|object', 'term'=>'T'],
'stripslashes_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'urldecode_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'urlencode_deep' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'wp_clear_scheduled_hook' => ['($wp_error is false ? 0|positive-int|false : 0|positive-int|\WP_Error)', 'args'=>$cronArgsType],
'addslashes_gpc' => ['T', '@phpstan-template' => 'T', 'gpc' => 'T'],
'get_objects_in_term' => [null, 'args' => 'array{order?: string}'],
'have_posts' => [null, '@phpstan-impure' => ''],
'rawurlencode_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'sanitize_category' => ['T', '@phpstan-template' => 'T of array|object', 'category' => 'T'],
'sanitize_post' => ['T', '@phpstan-template' => 'T of array|object', 'post' => 'T'],
'sanitize_term' => ['T', '@phpstan-template' => 'T of array|object', 'term' => 'T'],
'stripslashes_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'urldecode_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'urlencode_deep' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'wp_clear_scheduled_hook' => ['(0|positive-int|($wp_error is false ? false : \WP_Error))', 'args'=>$cronArgsType],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware PHPStan supported this syntax for conditional return types, nice

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me neither. It's great! It helps to simplify some of the conditions and make them easier to read.

'wp_get_schedule' => [null, 'args'=>$cronArgsType],
'wp_get_scheduled_event' => [null, 'args'=>$cronArgsType],
'WP_Http::get' => [$httpReturnType],
'WP_Http::head' => [$httpReturnType],
'WP_Http::post' => [$httpReturnType],
'WP_Http::request' => [$httpReturnType],
'WP_List_Table::display_tablenav' => ['void', 'which'=>'"top"|"bottom"'],
'WP_List_Table::pagination' => ['void', 'which'=>'"top"|"bottom"'],
'WP_List_Table::set_pagination_args' => ['void', 'args'=>'array{total_items?: int, total_pages?: int, per_page?: int}'],
'WP_List_Table::display_tablenav' => ['void', 'which' => '"top"|"bottom"'],
'WP_List_Table::pagination' => ['void', 'which' => '"top"|"bottom"'],
'WP_List_Table::set_pagination_args' => ['void', 'args' => 'array{total_items?: int, total_pages?: int, per_page?: int}'],
'wp_next_scheduled' => [null, 'args'=>$cronArgsType],
'WP_Post_Type::__construct' => ['void', 'args'=>'array<string, mixed>'],
'WP_Query::have_posts' => [null, '@phpstan-impure'=>''],
'WP_Query::have_posts' => [null, '@phpstan-impure' => ''],
'wp_remote_get' => [$httpReturnType],
'wp_remote_head' => [$httpReturnType],
'wp_remote_post' => [$httpReturnType],
Expand All @@ -56,26 +55,25 @@
'wp_safe_remote_request' => [$httpReturnType],
'wp_schedule_event' => ['($wp_error is false ? bool : true|\WP_Error)', 'args'=>$cronArgsType],
'wp_schedule_single_event' => ['($wp_error is false ? bool : true|\WP_Error)', 'args'=>$cronArgsType],
'wp_slash' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'WP_Taxonomy::__construct' => ['void', 'args'=>'array<string, mixed>'],
'wp_slash' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'wp_unschedule_event' => ['($wp_error is false ? bool : true|\WP_Error)', 'args'=>$cronArgsType],
'wp_unslash' => ['T', '@phpstan-template'=>'T', 'value'=>'T'],
'wp_unslash' => ['T', '@phpstan-template' => 'T', 'value' => 'T'],
'wp_widget_rss_form' => ['void', 'args'=>$wpWidgetRssFormArgsType, 'input'=>$wpWidgetRssFormInputType],
'WP_REST_Request' => [null, '@phpstan-template'=>'T of array', '@phpstan-implements'=>'ArrayAccess<key-of<T>, value-of<T>>'],
'WP_REST_Request::offsetExists' => [null, 'offset'=>'@param key-of<T>'],
'WP_REST_Request::offsetGet' => ['T[TOffset]', '@phpstan-template'=>'TOffset of key-of<T>', 'offset'=>'TOffset'],
'WP_REST_Request::offsetSet' => ['void', '@phpstan-template'=>'TOffset of key-of<T>', 'offset'=>'TOffset', 'value'=>'T[TOffset]'],
'WP_REST_Request::offsetUnset' => ['void', '@phpstan-template'=>'TOffset of key-of<T>', 'offset'=>'TOffset'],
'WP_REST_Request' => [null, '@phpstan-template' => 'T of array', '@phpstan-implements' => 'ArrayAccess<key-of<T>, value-of<T>>'],
'WP_REST_Request::offsetExists' => [null, 'offset' => '@param key-of<T>'],
'WP_REST_Request::offsetGet' => ['T[TOffset]', '@phpstan-template' => 'TOffset of key-of<T>', 'offset' => 'TOffset'],
'WP_REST_Request::offsetSet' => ['void', '@phpstan-template' => 'TOffset of key-of<T>', 'offset' => 'TOffset', 'value' => 'T[TOffset]'],
'WP_REST_Request::offsetUnset' => ['void', '@phpstan-template' => 'TOffset of key-of<T>', 'offset' => 'TOffset'],
'WP_Theme' => [null, '@phpstan-type'=>"ThemeKey 'Name'|'Version'|'Status'|'Title'|'Author'|'Author Name'|'Author URI'|'Description'|'Template'|'Stylesheet'|'Template Files'|'Stylesheet Files'|'Template Dir'|'Stylesheet Dir'|'Screenshot'|'Tags'|'Theme Root'|'Theme Root URI'|'Parent Theme'"],
'WP_Theme::get' => ["(\$header is 'Name'|'ThemeURI'|'Description'|'Author'|'AuthorURI'|'Version'|'Template'|'Status'|'Tags'|'TextDomain'|'DomainPath'|'RequiresWP'|'RequiresPHP'|'UpdateURI' ? (\$header is 'Tags' ? string[] : string) : false)"],
'WP_Theme::offsetExists' => ['($offset is ThemeKey ? true : false)'],
'WP_Theme::offsetGet' => ['($offset is ThemeKey ? mixed : null)'],
'WP_Block_List' => [null, '@phpstan-implements'=>'ArrayAccess<int, WP_Block>'],
'WP_Block_List::offsetExists' => [null, 'index'=>'int'],
'WP_Block_List::offsetGet' => ['WP_Block|null', 'index'=>'int'],
'WP_Block_List::offsetSet' => ['void', 'index'=>'int|null'],
'WP_Block_List::offsetUnset' => ['void', 'index'=>'int'],
'is_wp_error' => ['($thing is \WP_Error ? true : false)', '@phpstan-assert-if-true'=>'\WP_Error $thing'],
'WP_Block_List' => [null, '@phpstan-implements' => 'ArrayAccess<int, WP_Block>'],
'WP_Block_List::offsetExists' => [null, 'index' => 'int'],
'WP_Block_List::offsetGet' => ['WP_Block|null', 'index' => 'int'],
'WP_Block_List::offsetSet' => ['void', 'index' => 'int|null'],
'WP_Block_List::offsetUnset' => ['void', 'index' => 'int'],
'is_wp_error' => ['($thing is \WP_Error ? true : false)', '@phpstan-assert-if-true' => '\WP_Error $thing'],
'current_time' => ["(\$type is 'timestamp'|'U' ? int : string)"],
'mysql2date' => ["(\$format is 'G'|'U' ? int|false : string|false)"],
'get_post_types' => ["(\$output is 'names' ? array<int, string> : array<int, \WP_Post_Type>)"],
Expand All @@ -84,11 +82,11 @@
'get_attachment_taxonomies' => ["(\$output is 'names' ? array<int, string> : array<string, \WP_Taxonomy>)"],
'get_taxonomies_for_attachments' => ["(\$output is 'names' ? array<int, string> : array<string, \WP_Taxonomy>)"],
'get_post_stati' => ["(\$output is 'names' ? array<string, string> : array<string, \stdClass>)"],
'get_comment' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Comment|null))"],
'get_post' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Post|null))"],
'get_comment' => ["(\$comment is \WP_Comment ? array<array-key, mixed>|\WP_Comment : array<array-key, mixed>|\WP_Comment|null) & (\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Comment|null))", 'output'=>"'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'get_post' => ["(\$post is \WP_Post ? array<array-key, mixed>|\WP_Post : array<array-key, mixed>|\WP_Post|null) & (\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Post|null))", 'output'=>"'OBJECT'|'ARRAY_A'|'ARRAY_N'" ],
'get_term_by' => ["(\$output is 'ARRAY_A' ? array<string, string|int>|\WP_Error|false : (\$output is 'ARRAY_N' ? list<string|int>|\WP_Error|false : \WP_Term|\WP_Error|false))"],
'get_page_by_path' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|null : (\$output is 'ARRAY_N' ? array<int, mixed>|null : \WP_Post|null))"],
'get_term' => ["(\$output is 'ARRAY_A' ? array<string, string|int>|\WP_Error|null : (\$output is 'ARRAY_N' ? list<string|int>|\WP_Error|null : \WP_Term|\WP_Error|null))"],
'get_term' => ["(\$output is 'ARRAY_A' ? array<string, string|int>|\WP_Error|null : (\$output is 'ARRAY_N' ? list<string|int>|\WP_Error|null : \WP_Term|\WP_Error|null))", 'output'=>"'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'has_action' => ['($callback is false ? bool : false|int)'],
'has_filter' => ['($callback is false ? bool : false|int)'],
'get_permalink' => ['($post is \WP_Post ? string : string|false)'],
Expand Down Expand Up @@ -127,5 +125,10 @@
'WP_Filesystem_Base::dirlist' => [$filesystemDirlistReturnType],
'WP_Filesystem_SSH2::dirlist' => [$filesystemDirlistReturnType],
'WP_Filesystem_ftpsockets::dirlist' => [$filesystemDirlistReturnType],
'wpdb::prepare' => [null, 'query'=>'literal-string'],
'wpdb::prepare' => [null, 'query' => 'literal-string'],
'wpdb::get_row' => ["null|void|(\$output is 'ARRAY_A' ? array<string, mixed> : (\$output is 'ARRAY_N' ? array<int, mixed> : \stdClass))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'", 'y' => '0|positive-int'],
'wpdb::get_results' => ["null|(\$output is 'ARRAY_A' ? array<string, mixed> : (\$output is 'ARRAY_N' ? array<int, mixed> : (\$output is 'OBJECT_K' ? array<string, \stdClass> : \stdClass)))", 'output' => "'OBJECT'|'OBJECT_K'|'ARRAY_A'|'ARRAY_N'"],
'get_bookmark' => ["null|(\$output is 'ARRAY_A' ? array<string, mixed> : (\$output is 'ARRAY_N' ? array<int, mixed> : \stdClass))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'get_category' => ["(\$category is object ? array<array-key, mixed>|\WP_Term : array<array-key, mixed>|\WP_Term|\WP_Error|null) & (\$output is 'ARRAY_A' ? array<string, mixed>|\WP_Error|null : (\$output is 'ARRAY_N' ? array<int, mixed>|\WP_Error|null : \WP_Term|\WP_Error|null))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
'get_category_by_path' => ["(\$output is 'ARRAY_A' ? array<string, mixed>|\WP_Error|null : (\$output is 'ARRAY_N' ? array<int, mixed>|\WP_Error|null : \WP_Term|\WP_Error|null))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"],
];
5 changes: 5 additions & 0 deletions tests/TypeInferenceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/current_time.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/echo_parameter.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_attachment_taxonomies.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_bookmark.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_category.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_category_by_path.php');
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');
Expand All @@ -27,8 +30,10 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/is_wp_error.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/mysql2date.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/term_exists.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_clear_scheduled_hook.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_error_parameter.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_theme.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/wpdb.php');
}

/**
Expand Down
16 changes: 16 additions & 0 deletions tests/data/get_bookmark.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function get_bookmark;
use function PHPStan\Testing\assertType;

/** @var \stdClass|int $bookmark */
$bookmark;

assertType('stdClass|null', get_bookmark($bookmark));
assertType('stdClass|null', get_bookmark($bookmark, 'OBJECT'));
assertType('array<string, mixed>|null', get_bookmark($bookmark, 'ARRAY_A'));
assertType('array<int, mixed>|null', get_bookmark($bookmark, 'ARRAY_N'));
24 changes: 24 additions & 0 deletions tests/data/get_category.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function get_category;
use function PHPStan\Testing\assertType;

/** @var object $category */
$category;

assertType('WP_Term', get_category($category));
assertType('WP_Term', get_category($category, 'OBJECT'));
assertType('array<string, mixed>', get_category($category, 'ARRAY_A'));
assertType('array<int, mixed>', get_category($category, 'ARRAY_N'));

/** @var int|object $category */
$category;

assertType('WP_Error|WP_Term|null', get_category($category));
assertType('WP_Error|WP_Term|null', get_category($category, 'OBJECT'));
assertType('array<string, mixed>|WP_Error|null', get_category($category, 'ARRAY_A'));
assertType('array<int, mixed>|WP_Error|null', get_category($category, 'ARRAY_N'));
16 changes: 16 additions & 0 deletions tests/data/get_category_by_path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function get_category_by_path;
use function PHPStan\Testing\assertType;

/** @var bool $bool */
$bool;

assertType('WP_Error|WP_Term|null', get_category_by_path('', $bool, ));
assertType('WP_Error|WP_Term|null', get_category_by_path('', $bool, 'OBJECT'));
assertType('array<string, mixed>|WP_Error|null', get_category_by_path('', $bool, 'ARRAY_A'));
assertType('array<int, mixed>|WP_Error|null', get_category_by_path('', $bool, 'ARRAY_N'));
20 changes: 11 additions & 9 deletions tests/data/get_comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@
use function get_comment;
use function PHPStan\Testing\assertType;

/** @var \WP_Comment|int $comment */
$comment = $comment;
/** @var \WP_Comment|int|string|null $comment */
$comment;

// Default output
assertType('WP_Comment|null', get_comment());
assertType('WP_Comment|null', get_comment($comment));
assertType('WP_Comment|null', get_comment($comment, OBJECT));
assertType('WP_Comment|null', get_comment($comment, 'OBJECT'));

// Associative array output
assertType('array<string, mixed>|null', get_comment($comment, ARRAY_A));
assertType('array<string, mixed>|null', get_comment($comment, 'ARRAY_A'));

// Numeric array output
assertType('array<int, mixed>|null', get_comment($comment, ARRAY_N));
assertType('array<int, mixed>|null', get_comment($comment, 'ARRAY_N'));

// Unknown output
assertType('array<int|string, mixed>|WP_Comment|null', get_comment($comment, (string)$_GET['unknown_string']));
/** @var \WP_Comment $comment */
$comment;

// Unexpected output
assertType('WP_Comment|null', get_comment($comment, 'Hello'));
assertType('WP_Comment', get_comment($comment));
assertType('WP_Comment', get_comment($comment, 'OBJECT'));
assertType('array<string, mixed>', get_comment($comment, 'ARRAY_A'));
assertType('array<int, mixed>', get_comment($comment, 'ARRAY_N'));
18 changes: 10 additions & 8 deletions tests/data/get_post.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,23 @@
use function PHPStan\Testing\assertType;

/** @var \WP_Post|int|null $post */
$post = $post;
$post;

// Default output
assertType('WP_Post|null', get_post());
assertType('WP_Post|null', get_post($post));
assertType('WP_Post|null', get_post($post, OBJECT));
assertType('WP_Post|null', get_post($post, 'OBJECT'));

// Associative array output
assertType('array<string, mixed>|null', get_post($post, ARRAY_A));
assertType('array<string, mixed>|null', get_post($post, 'ARRAY_A'));

// Numeric array output
assertType('array<int, mixed>|null', get_post($post, ARRAY_N));
assertType('array<int, mixed>|null', get_post($post, 'ARRAY_N'));

// Unknown output
assertType('array<int|string, mixed>|WP_Post|null', get_post($post, (string)$_GET['unknown_string']));
/** @var \WP_Post $post */
$post;

// Unexpected output
assertType('WP_Post|null', get_post($post, 'Hello'));
assertType('WP_Post', get_post($post));
assertType('WP_Post', get_post($post, 'OBJECT'));
assertType('array<string, mixed>', get_post($post, 'ARRAY_A'));
assertType('array<int, mixed>', get_post($post, 'ARRAY_N'));
2 changes: 1 addition & 1 deletion tests/data/get_term.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
assertType( 'array<string, int|string>|WP_Error|null', get_term( 2, '', ARRAY_A ) );
assertType( 'array<string, int|string>|WP_Error|null', get_term( 2, 'category', ARRAY_A ) );
assertType( 'array<int, int|string>|WP_Error|null', get_term( 2, '', ARRAY_N ) );
assertType( 'array<int, int|string>|WP_Error|null', get_term( 2, 'category', ARRAY_N ) );
assertType( 'array<int, int|string>|WP_Error|null', get_term( 2, 'category', ARRAY_N ) );
12 changes: 12 additions & 0 deletions tests/data/wp_clear_scheduled_hook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use function wp_clear_scheduled_hook;
use function PHPStan\Testing\assertType;

assertType('int<0, max>|false', wp_clear_scheduled_hook('hook', []));
assertType('int<0, max>|false', wp_clear_scheduled_hook('hook', [], false));
assertType('int<0, max>|WP_Error', wp_clear_scheduled_hook('hook', [], true));
21 changes: 21 additions & 0 deletions tests/data/wpdb.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace PhpStubs\WordPress\Core\Tests;

use wpdb;
use function PHPStan\Testing\assertType;

// wpdb::get_row()
assertType('stdClass|void|null', wpdb::get_row());
assertType('stdClass|void|null', wpdb::get_row(null, 'OBJECT'));
assertType('array<string, mixed>|void|null', wpdb::get_row(null, 'ARRAY_A'));
assertType('array<int, mixed>|void|null', wpdb::get_row(null, 'ARRAY_N'));

// wpdb::get_results()
assertType('stdClass|null', wpdb::get_results());
assertType('stdClass|null', wpdb::get_results(null, 'OBJECT'));
assertType('array<string, stdClass>|null', wpdb::get_results(null, 'OBJECT_K'));
assertType('array<string, mixed>|null', wpdb::get_results(null, 'ARRAY_A'));
assertType('array<int, mixed>|null', wpdb::get_results(null, 'ARRAY_N'));
Loading