1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Analyser;
4:
5: use PHPStan\Turbo\ShadowedByTurboExtension;
6: use PHPStan\Type\Type;
7:
8: /**
9: * Object of this class is one of the parameters of `NodeScopeResolver::processStmtNodes()`.
10: *
11: * It determines whether loops will be analysed once or multiple times
12: * until the types "stabilize".
13: *
14: * When in doubt, use `StatementContext::createTopLevel()`.
15: */
16: #[ShadowedByTurboExtension(implementation: __DIR__ . '/../../turbo-ext/src/StatementContext.cpp')]
17: final class StatementContext
18: {
19:
20: private function __construct(
21: private bool $isTopLevel,
22: private int $foreachUnrollFactor = 1,
23: private bool $resolveTemplateArguments = true,
24: private ?Type $expectedReturnType = null,
25: private ?Type $nativeExpectedReturnType = null,
26: )
27: {
28: }
29:
30: /**
31: * @api
32: */
33: public static function createTopLevel(bool $resolveTemplateArguments = true): self
34: {
35: return new self(true, resolveTemplateArguments: $resolveTemplateArguments);
36: }
37:
38: /**
39: * @api
40: */
41: public static function createDeep(bool $resolveTemplateArguments = true): self
42: {
43: return new self(false, resolveTemplateArguments: $resolveTemplateArguments);
44: }
45:
46: public function isTopLevel(): bool
47: {
48: return $this->isTopLevel;
49: }
50:
51: public function getForeachUnrollFactor(): int
52: {
53: return $this->foreachUnrollFactor;
54: }
55:
56: public function shouldResolveTemplateArguments(): bool
57: {
58: return $this->resolveTemplateArguments;
59: }
60:
61: public function withoutTemplateArgumentResolution(): self
62: {
63: if (!$this->resolveTemplateArguments) {
64: return $this;
65: }
66:
67: return new self($this->isTopLevel, $this->foreachUnrollFactor, false, $this->expectedReturnType, $this->nativeExpectedReturnType);
68: }
69:
70: /**
71: * The type the returned expressions of an anonymous function are expected
72: * to have, from the callable type it is passed to - an expected type for
73: * the closures, arrow functions and array literals it returns.
74: */
75: public function withExpectedReturnType(?Type $expectedReturnType, ?Type $nativeExpectedReturnType): self
76: {
77: if ($expectedReturnType === null && $nativeExpectedReturnType === null) {
78: return $this;
79: }
80:
81: return new self($this->isTopLevel, $this->foreachUnrollFactor, $this->resolveTemplateArguments, $expectedReturnType, $nativeExpectedReturnType);
82: }
83:
84: public function getExpectedReturnType(): ?Type
85: {
86: return $this->expectedReturnType;
87: }
88:
89: public function getNativeExpectedReturnType(): ?Type
90: {
91: return $this->nativeExpectedReturnType;
92: }
93:
94: public function enterDeep(): self
95: {
96: if ($this->isTopLevel) {
97: return new self(false, $this->foreachUnrollFactor, $this->resolveTemplateArguments, $this->expectedReturnType, $this->nativeExpectedReturnType);
98: }
99:
100: return $this;
101: }
102:
103: public function enterUnrolledForeach(int $totalKeys): self
104: {
105: return new self($this->isTopLevel, $this->foreachUnrollFactor * $totalKeys, $this->resolveTemplateArguments, $this->expectedReturnType, $this->nativeExpectedReturnType);
106: }
107:
108: }
109: