Skip to content

Commit 7574a5b

Browse files
authored
Introduce a dynamic return type extension for has_filter() and has_action() (#93)
1 parent 265d06b commit 7574a5b

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

extension.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ services:
4343
class: SzepeViktor\PHPStan\WordPress\GetCommentDynamicFunctionReturnTypeExtension
4444
tags:
4545
- phpstan.broker.dynamicFunctionReturnTypeExtension
46+
-
47+
class: SzepeViktor\PHPStan\WordPress\HasFilterDynamicFunctionReturnTypeExtension
48+
tags:
49+
- phpstan.broker.dynamicFunctionReturnTypeExtension
4650
-
4751
class: SzepeViktor\PHPStan\WordPress\ShortcodeAttsDynamicFunctionReturnTypeExtension
4852
tags:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
/**
4+
* Set return type of has_filter() and has_action().
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace SzepeViktor\PHPStan\WordPress;
10+
11+
use PhpParser\Node\Expr\FuncCall;
12+
use PHPStan\Analyser\Scope;
13+
use PHPStan\Reflection\FunctionReflection;
14+
use PHPStan\Type\Type;
15+
use PHPStan\Type\BooleanType;
16+
use PHPStan\Type\Constant\ConstantBooleanType;
17+
use PHPStan\Type\IntegerType;
18+
use PHPStan\Type\MixedType;
19+
use PHPStan\Type\TypeCombinator;
20+
21+
class HasFilterDynamicFunctionReturnTypeExtension implements \PHPStan\Type\DynamicFunctionReturnTypeExtension
22+
{
23+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
24+
{
25+
return in_array($functionReflection->getName(), ['has_filter', 'has_action'], true);
26+
}
27+
28+
// phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter
29+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
30+
{
31+
$args = $functionCall->getArgs();
32+
$callbackArgumentType = new ConstantBooleanType(false);
33+
34+
if (isset($args[1])) {
35+
$callbackArgumentType = $scope->getType($args[1]->value);
36+
}
37+
38+
if (($callbackArgumentType instanceof ConstantBooleanType) && ($callbackArgumentType->getValue() === false)) {
39+
return new BooleanType();
40+
}
41+
42+
if ($callbackArgumentType instanceof MixedType) {
43+
return TypeCombinator::union(
44+
new BooleanType(),
45+
new IntegerType()
46+
);
47+
}
48+
49+
return TypeCombinator::union(
50+
new ConstantBooleanType(false),
51+
new IntegerType()
52+
);
53+
}
54+
}

tests/DynamicReturnTypeExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public function dataFileAsserts(): iterable
1919
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_object_taxonomies.php');
2020
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_post.php');
2121
yield from $this->gatherAssertTypes(__DIR__ . '/data/get_terms.php');
22+
yield from $this->gatherAssertTypes(__DIR__ . '/data/has_filter.php');
2223
yield from $this->gatherAssertTypes(__DIR__ . '/data/mysql2date.php');
2324
yield from $this->gatherAssertTypes(__DIR__ . '/data/shortcode_atts.php');
2425
yield from $this->gatherAssertTypes(__DIR__ . '/data/term_exists.php');

tests/data/has_filter.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SzepeViktor\PHPStan\WordPress\Tests;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
// Default callback of false
10+
assertType('bool', has_filter(''));
11+
assertType('bool', has_action(''));
12+
13+
// Explicit callback of false
14+
assertType('bool', has_filter('', false));
15+
assertType('bool', has_action('', false));
16+
17+
// Explicit callback
18+
assertType('int|false', has_filter('', 'intval'));
19+
assertType('int|false', has_action('', 'intval'));
20+
21+
// Unknown callback
22+
$callback = $_GET['callback'] ?? 'foo';
23+
assertType('bool|int', has_filter('', $callback));
24+
assertType('bool|int', has_action('', $callback));

0 commit comments

Comments
 (0)