1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: final class TypeTraverser
6: {
7:
8: /** @var callable(Type $type, callable(Type): Type $traverse): Type */
9: private $cb;
10:
11: /**
12: * Map a Type recursively
13: *
14: * For every Type instance, the callback can return a new Type, and/or
15: * decide to traverse inner types or to ignore them.
16: *
17: * The following example converts constant strings to objects, while
18: * preserving unions and intersections:
19: *
20: * TypeTraverser::map($type, function (Type $type, callable $traverse): Type {
21: * if ($type instanceof UnionType || $type instanceof IntersectionType) {
22: * // Traverse inner types
23: * return $traverse($type);
24: * }
25: * if ($type instanceof ConstantStringType) {
26: * // Replaces the current type, and don't traverse
27: * return new ObjectType($type->getValue());
28: * }
29: * // Replaces the current type, and don't traverse
30: * return new MixedType();
31: * });
32: *
33: * @api
34: * @param callable(Type $type, callable(Type): Type $traverse): Type $cb
35: */
36: public static function map(Type $type, callable $cb): Type
37: {
38: $self = new self($cb);
39:
40: return $self->mapInternal($type);
41: }
42:
43: /** @param callable(Type $type, callable(Type): Type $traverse): Type $cb */
44: private function __construct(callable $cb)
45: {
46: $this->cb = $cb;
47: }
48:
49: /** @internal */
50: public function mapInternal(Type $type): Type
51: {
52: return ($this->cb)($type, [$this, 'traverseInternal']);
53: }
54:
55: /** @internal */
56: public function traverseInternal(Type $type): Type
57: {
58: return $type->traverse([$this, 'mapInternal']);
59: }
60:
61: }
62: