Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 37fe25b

Browse files
committed
Improve idate() return types
1 parent 6f87293 commit 37fe25b

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr\FuncCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\DependencyInjection\AutowiredService;
8+
use PHPStan\Reflection\FunctionReflection;
9+
use PHPStan\Type\Constant\ConstantBooleanType;
10+
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
11+
use PHPStan\Type\Type;
12+
13+
#[AutowiredService]
14+
final class IdateFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
15+
{
16+
17+
public function __construct(private IdateFunctionReturnTypeHelper $idateFunctionReturnTypeHelper)
18+
{
19+
}
20+
21+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
22+
{
23+
return $functionReflection->getName() === 'idate';
24+
}
25+
26+
public function getTypeFromFunctionCall(
27+
FunctionReflection $functionReflection,
28+
FuncCall $functionCall,
29+
Scope $scope,
30+
): Type
31+
{
32+
$args = $functionCall->getArgs();
33+
if ($args === []) {
34+
return new ConstantBooleanType(false);
35+
}
36+
37+
return $this->idateFunctionReturnTypeHelper->getTypeFromFormatType(
38+
$scope->getType($args[0]->value),
39+
);
40+
}
41+
42+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PHPStan\DependencyInjection\AutowiredService;
6+
use PHPStan\Type\Constant\ConstantBooleanType;
7+
use PHPStan\Type\IntegerRangeType;
8+
use PHPStan\Type\IntegerType;
9+
use PHPStan\Type\Type;
10+
use PHPStan\Type\TypeCombinator;
11+
12+
#[AutowiredService]
13+
final class IdateFunctionReturnTypeHelper
14+
{
15+
16+
public function getTypeFromFormatType(Type $formatType): Type
17+
{
18+
$types = [];
19+
foreach ($formatType->getConstantStrings() as $formatString) {
20+
$types[] = $this->buildReturnTypeFromFormat($formatString->getValue());
21+
}
22+
23+
if ($types === []) {
24+
$types = [new IntegerType(), new ConstantBooleanType(false)];
25+
}
26+
27+
return TypeCombinator::union(...$types);
28+
}
29+
30+
public function buildReturnTypeFromFormat(string $formatString): Type
31+
{
32+
// see https://www.php.net/idate
33+
return match ($formatString) {
34+
'd' => IntegerRangeType::fromInterval(1, 31),
35+
'h' => IntegerRangeType::fromInterval(1, 12),
36+
'H' => IntegerRangeType::fromInterval(0, 23),
37+
'i' => IntegerRangeType::fromInterval(0, 59),
38+
'I' => IntegerRangeType::fromInterval(0, 1),
39+
'L' => IntegerRangeType::fromInterval(0, 1),
40+
'm' => IntegerRangeType::fromInterval(1, 12),
41+
'N' => IntegerRangeType::fromInterval(1, 7),
42+
's' => IntegerRangeType::fromInterval(0, 59),
43+
't' => IntegerRangeType::fromInterval(28, 31),
44+
'w' => IntegerRangeType::fromInterval(0, 6),
45+
'W' => IntegerRangeType::fromInterval(1, 53),
46+
'y' => IntegerRangeType::fromInterval(0, 99),
47+
'z' => IntegerRangeType::fromInterval(0, 365),
48+
'B', 'o', 'U', 'Y', 'Z' => new IntegerType(),
49+
default => new ConstantBooleanType(false),
50+
};
51+
}
52+
53+
}

‎tests/PHPStan/Analyser/nsrt/idate.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace PHPStan\Analyser\nsrt;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
10+
/**
11+
* @param 'h'|'H' $hour
12+
* @param 'm'|string $format
13+
*/
14+
public function doFoo(string $string, string $hour, string $format): void
15+
{
16+
assertType('int<1, 7>', idate('N'));
17+
assertType('int', idate('Y'));
18+
assertType('false', idate('wrong'));
19+
assertType('false', idate(''));
20+
assertType('int|false', idate($string));
21+
assertType('int<0, 23>', idate($hour));
22+
assertType('int|false', idate($format));
23+
}
24+
25+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /