1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Constant;
4:
5: use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode;
6: use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
7: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
8: use PHPStan\Type\ConstantScalarType;
9: use PHPStan\Type\FloatType;
10: use PHPStan\Type\GeneralizePrecision;
11: use PHPStan\Type\Traits\ConstantNumericComparisonTypeTrait;
12: use PHPStan\Type\Traits\ConstantScalarTypeTrait;
13: use PHPStan\Type\Type;
14: use PHPStan\Type\VerbosityLevel;
15: use function abs;
16: use function ini_get;
17: use function ini_set;
18: use function is_finite;
19: use function is_nan;
20: use function str_contains;
21:
22: /** @api */
23: class ConstantFloatType extends FloatType implements ConstantScalarType
24: {
25:
26: use ConstantScalarTypeTrait;
27: use ConstantScalarToBooleanTrait;
28: use ConstantNumericComparisonTypeTrait;
29:
30: /** @api */
31: public function __construct(private float $value)
32: {
33: parent::__construct();
34: }
35:
36: public function getValue(): float
37: {
38: return $this->value;
39: }
40:
41: public function equals(Type $type): bool
42: {
43: return $type instanceof self && ($this->value === $type->value || is_nan($this->value) && is_nan($type->value));
44: }
45:
46: private function castFloatToString(float $value): string
47: {
48: $precisionBackup = ini_get('precision');
49: ini_set('precision', '-1');
50: try {
51: $valueStr = (string) $value;
52: if (is_finite($value) && !str_contains($valueStr, '.')) {
53: $valueStr .= '.0';
54: }
55:
56: return $valueStr;
57: } finally {
58: ini_set('precision', $precisionBackup);
59: }
60: }
61:
62: public function describe(VerbosityLevel $level): string
63: {
64: return $level->handle(
65: static fn (): string => 'float',
66: fn (): string => $this->castFloatToString($this->value),
67: );
68: }
69:
70: public function toString(): Type
71: {
72: return new ConstantStringType((string) $this->value);
73: }
74:
75: public function toInteger(): Type
76: {
77: return new ConstantIntegerType((int) $this->value);
78: }
79:
80: public function toAbsoluteNumber(): Type
81: {
82: return new self(abs($this->value));
83: }
84:
85: public function toArrayKey(): Type
86: {
87: return new ConstantIntegerType((int) $this->value);
88: }
89:
90: public function generalize(GeneralizePrecision $precision): Type
91: {
92: return new FloatType();
93: }
94:
95: /**
96: * @return ConstTypeNode
97: */
98: public function toPhpDocNode(): TypeNode
99: {
100: return new ConstTypeNode(new ConstExprFloatNode($this->castFloatToString($this->value)));
101: }
102:
103: }
104: