1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Reflection;
4:
5: use PhpParser\Node\Stmt\ClassMethod;
6: use PhpParser\Node\Stmt\Function_;
7: use PHPStan\Analyser\Scope;
8: use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction;
9: use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter;
10: use PHPStan\BetterReflection\Reflection\ReflectionConstant;
11: use function array_slice;
12: use function count;
13: use function explode;
14: use function implode;
15: use function sprintf;
16:
17: /** @api */
18: class InitializerExprContext implements NamespaceAnswerer
19: {
20:
21: private function __construct(
22: private ?string $file,
23: private ?string $namespace,
24: private ?string $className,
25: private ?string $traitName,
26: private ?string $function,
27: private ?string $method,
28: )
29: {
30: }
31:
32: public static function fromScope(Scope $scope): self
33: {
34: return new self(
35: $scope->getFile(),
36: $scope->getNamespace(),
37: $scope->isInClass() ? $scope->getClassReflection()->getName() : null,
38: $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null,
39: $scope->isInAnonymousFunction() ? '{closure}' : ($scope->getFunction() !== null ? $scope->getFunction()->getName() : null),
40: $scope->isInAnonymousFunction() ? '{closure}' : ($scope->getFunction() instanceof MethodReflection
41: ? sprintf('%s::%s', $scope->getFunction()->getDeclaringClass()->getName(), $scope->getFunction()->getName())
42: : ($scope->getFunction() instanceof FunctionReflection ? $scope->getFunction()->getName() : null)),
43: );
44: }
45:
46: private static function parseNamespace(string $name): ?string
47: {
48: $parts = explode('\\', $name);
49: if (count($parts) > 1) {
50: return implode('\\', array_slice($parts, 0, -1));
51: }
52:
53: return null;
54: }
55:
56: public static function fromClassReflection(ClassReflection $classReflection): self
57: {
58: return self::fromClass($classReflection->getName(), $classReflection->getFileName());
59: }
60:
61: public static function fromClass(string $className, ?string $fileName): self
62: {
63: return new self(
64: $fileName,
65: self::parseNamespace($className),
66: $className,
67: null,
68: null,
69: null,
70: );
71: }
72:
73: public static function fromReflectionParameter(ReflectionParameter $parameter): self
74: {
75: $declaringFunction = $parameter->getDeclaringFunction();
76: if ($declaringFunction instanceof ReflectionFunction) {
77: $file = $declaringFunction->getFileName();
78: return new self(
79: $file === false ? null : $file,
80: self::parseNamespace($declaringFunction->getName()),
81: null,
82: null,
83: $declaringFunction->getName(),
84: $declaringFunction->getName(),
85: );
86: }
87:
88: $file = $declaringFunction->getFileName();
89:
90: $betterReflection = $declaringFunction->getBetterReflection();
91:
92: return new self(
93: $file === false ? null : $file,
94: self::parseNamespace($betterReflection->getDeclaringClass()->getName()),
95: $declaringFunction->getDeclaringClass()->getName(),
96: $betterReflection->getDeclaringClass()->isTrait() ? $betterReflection->getDeclaringClass()->getName() : null,
97: $declaringFunction->getName(),
98: sprintf('%s::%s', $declaringFunction->getDeclaringClass()->getName(), $declaringFunction->getName()),
99: );
100: }
101:
102: public static function fromStubParameter(
103: ?string $className,
104: string $stubFile,
105: ClassMethod|Function_ $function,
106: ): self
107: {
108: $namespace = null;
109: if ($className !== null) {
110: $namespace = self::parseNamespace($className);
111: } else {
112: if ($function instanceof Function_ && $function->namespacedName !== null) {
113: $namespace = self::parseNamespace($function->namespacedName->toString());
114: }
115: }
116: return new self(
117: $stubFile,
118: $namespace,
119: $className,
120: null,
121: $function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : ($function instanceof ClassMethod ? $function->name->toString() : null),
122: $function instanceof ClassMethod && $className !== null
123: ? sprintf('%s::%s', $className, $function->name->toString())
124: : ($function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : null),
125: );
126: }
127:
128: public static function fromGlobalConstant(ReflectionConstant $constant): self
129: {
130: return new self(
131: $constant->getFileName(),
132: $constant->getNamespaceName(),
133: null,
134: null,
135: null,
136: null,
137: );
138: }
139:
140: public static function createEmpty(): self
141: {
142: return new self(null, null, null, null, null, null);
143: }
144:
145: public function getFile(): ?string
146: {
147: return $this->file;
148: }
149:
150: public function getClassName(): ?string
151: {
152: return $this->className;
153: }
154:
155: public function getNamespace(): ?string
156: {
157: return $this->namespace;
158: }
159:
160: public function getTraitName(): ?string
161: {
162: return $this->traitName;
163: }
164:
165: public function getFunction(): ?string
166: {
167: return $this->function;
168: }
169:
170: public function getMethod(): ?string
171: {
172: return $this->method;
173: }
174:
175: }
176: