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: $className = $classReflection->getName();
59:
60: return new self(
61: $classReflection->getFileName(),
62: self::parseNamespace($className),
63: $className,
64: null,
65: null,
66: null,
67: );
68: }
69:
70: public static function fromReflectionParameter(ReflectionParameter $parameter): self
71: {
72: $declaringFunction = $parameter->getDeclaringFunction();
73: if ($declaringFunction instanceof ReflectionFunction) {
74: $file = $declaringFunction->getFileName();
75: return new self(
76: $file === false ? null : $file,
77: self::parseNamespace($declaringFunction->getName()),
78: null,
79: null,
80: $declaringFunction->getName(),
81: $declaringFunction->getName(),
82: );
83: }
84:
85: $file = $declaringFunction->getFileName();
86:
87: $betterReflection = $declaringFunction->getBetterReflection();
88:
89: return new self(
90: $file === false ? null : $file,
91: self::parseNamespace($betterReflection->getDeclaringClass()->getName()),
92: $declaringFunction->getDeclaringClass()->getName(),
93: $betterReflection->getDeclaringClass()->isTrait() ? $betterReflection->getDeclaringClass()->getName() : null,
94: $declaringFunction->getName(),
95: sprintf('%s::%s', $declaringFunction->getDeclaringClass()->getName(), $declaringFunction->getName()),
96: );
97: }
98:
99: public static function fromStubParameter(
100: ?string $className,
101: string $stubFile,
102: ClassMethod|Function_ $function,
103: ): self
104: {
105: $namespace = null;
106: if ($className !== null) {
107: $namespace = self::parseNamespace($className);
108: } else {
109: if ($function instanceof Function_ && $function->namespacedName !== null) {
110: $namespace = self::parseNamespace($function->namespacedName->toString());
111: }
112: }
113: return new self(
114: $stubFile,
115: $namespace,
116: $className,
117: null,
118: $function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : ($function instanceof ClassMethod ? $function->name->toString() : null),
119: $function instanceof ClassMethod && $className !== null
120: ? sprintf('%s::%s', $className, $function->name->toString())
121: : ($function instanceof Function_ && $function->namespacedName !== null ? $function->namespacedName->toString() : null),
122: );
123: }
124:
125: public static function fromGlobalConstant(ReflectionConstant $constant): self
126: {
127: return new self(
128: $constant->getFileName(),
129: $constant->getNamespaceName(),
130: null,
131: null,
132: null,
133: null,
134: );
135: }
136:
137: public static function createEmpty(): self
138: {
139: return new self(null, null, null, null, null, null);
140: }
141:
142: public function getFile(): ?string
143: {
144: return $this->file;
145: }
146:
147: public function getClassName(): ?string
148: {
149: return $this->className;
150: }
151:
152: public function getNamespace(): ?string
153: {
154: return $this->namespace;
155: }
156:
157: public function getTraitName(): ?string
158: {
159: return $this->traitName;
160: }
161:
162: public function getFunction(): ?string
163: {
164: return $this->function;
165: }
166:
167: public function getMethod(): ?string
168: {
169: return $this->method;
170: }
171:
172: }
173: