1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: /**
6: * Controls how aggressively Type::generalize() widens a type.
7: *
8: * Generalization is the process of widening a specific type to a broader one.
9: * For example, generalizing ConstantStringType('hello') yields StringType.
10: * This is used when PHPStan needs to merge types across loop iterations or
11: * branches where tracking precise constant values is impractical.
12: *
13: * Three levels of precision:
14: * - **lessSpecific**: Aggressive generalization — constant values become their
15: * general type (e.g. 'hello' → string, array{foo: int} → array<string, int>)
16: * - **moreSpecific**: Preserves more detail — e.g. non-empty-string stays
17: * non-empty-string instead of widening to string
18: * - **templateArgument**: Used when generalizing template type arguments,
19: * preserving template-specific structure
20: *
21: * Used as a parameter to Type::generalize():
22: *
23: * $type->generalize(GeneralizePrecision::lessSpecific())
24: */
25: final class GeneralizePrecision
26: {
27:
28: private const LESS_SPECIFIC = 1;
29: private const MORE_SPECIFIC = 2;
30: private const TEMPLATE_ARGUMENT = 3;
31:
32: /** @var self[] */
33: private static array $registry;
34:
35: private function __construct(private int $value)
36: {
37: }
38:
39: private static function create(int $value): self
40: {
41: self::$registry[$value] ??= new self($value);
42: return self::$registry[$value];
43: }
44:
45: /** @api */
46: public static function lessSpecific(): self
47: {
48: return self::create(self::LESS_SPECIFIC);
49: }
50:
51: /** @api */
52: public static function moreSpecific(): self
53: {
54: return self::create(self::MORE_SPECIFIC);
55: }
56:
57: /** @api */
58: public static function templateArgument(): self
59: {
60: return self::create(self::TEMPLATE_ARGUMENT);
61: }
62:
63: public function isMoreSpecific(): bool
64: {
65: return $this->value === self::MORE_SPECIFIC;
66: }
67:
68: public function isTemplateArgument(): bool
69: {
70: return $this->value === self::TEMPLATE_ARGUMENT;
71: }
72:
73: }
74: