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