expr, $context); } $constantName = null; if ( $node instanceof Node\Expr\ConstFetch && ! in_array($node->name->toLowerString(), self::TRUE_FALSE_NULL, true) ) { $constantName = $this->resolveConstantName($node, $context); } elseif ($node instanceof Node\Expr\ClassConstFetch) { $constantName = $this->resolveClassConstantName($node, $context); } $constExprEvaluator = new ConstExprEvaluator(function (Node\Expr $node) use ($context, $constantName): mixed { if ($node instanceof Node\Expr\ConstFetch) { return $this->getConstantValue($node, $constantName, $context); } if ($node instanceof Node\Expr\ClassConstFetch) { return $this->getClassConstantValue($node, $constantName, $context); } if ($node instanceof Node\Expr\New_) { throw Exception\UnableToCompileNode::becauseOfInitializer($context, $node); } if ($node instanceof Node\Scalar\MagicConst\Dir) { return $this->compileDirConstant($context, $node); } if ($node instanceof Node\Scalar\MagicConst\File) { return $this->compileFileConstant($context, $node); } if ($node instanceof Node\Scalar\MagicConst\Class_) { return $this->compileClassConstant($context); } if ($node instanceof Node\Scalar\MagicConst\Line) { return $node->getLine(); } if ($node instanceof Node\Scalar\MagicConst\Namespace_) { return $context->getNamespace() ?? ''; } if ($node instanceof Node\Scalar\MagicConst\Method) { $class = $context->getClass(); $function = $context->getFunction(); if ($class !== null && $function !== null) { return sprintf('%s::%s', $class->getName(), $function->getName()); } if ($function !== null) { return $function->getName(); } return ''; } if ($node instanceof Node\Scalar\MagicConst\Function_) { return $context->getFunction()?->getName() ?? ''; } if ($node instanceof Node\Scalar\MagicConst\Trait_) { $class = $context->getClass(); if ($class !== null && $class->isTrait()) { return $class->getName(); } return ''; } if ( $node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name && $node->name->toLowerString() === 'constant' && $node->args[0] instanceof Node\Arg && $node->args[0]->value instanceof Node\Scalar\String_ && defined($node->args[0]->value->value) ) { return constant($node->args[0]->value->value); } if ( $node instanceof Node\Expr\PropertyFetch && $node->var instanceof Node\Expr\ClassConstFetch ) { return $this->getEnumPropertyValue($node, $context); } throw Exception\UnableToCompileNode::forUnRecognizedExpressionInContext($node, $context); }); /** @psalm-var mixed $value */ $value = $constExprEvaluator->evaluateDirectly($node); return new CompiledValue($value, $constantName); } private function getEnumPropertyValue(Node\Expr\PropertyFetch $node, CompilerContext $context): mixed { assert($node->var instanceof Node\Expr\ClassConstFetch); assert($node->var->class instanceof Node\Name); $className = $this->resolveClassName($node->var->class->toString(), $context); $class = $context->getReflector()->reflectClass($className); if (! $class instanceof ReflectionEnum) { throw Exception\UnableToCompileNode::becauseOfInvalidEnumCasePropertyFetch($context, $class, $node); } assert($node->var->name instanceof Node\Identifier); $caseName = $node->var->name->name; assert($caseName !== ''); $case = $class->getCase($caseName); if ($case === null) { throw Exception\UnableToCompileNode::becauseOfInvalidEnumCasePropertyFetch($context, $class, $node); } assert($node->name instanceof Node\Identifier); return match ($node->name->toString()) { 'value' => $case->getValue(), 'name' => $case->getName(), default => throw Exception\UnableToCompileNode::becauseOfInvalidEnumCasePropertyFetch($context, $class, $node), }; } private function resolveConstantName(Node\Expr\ConstFetch $constNode, CompilerContext $context): string { $constantName = $constNode->name->toString(); $namespace = $context->getNamespace() ?? ''; if ($constNode->name->isUnqualified()) { $namespacedConstantName = sprintf('%s\\%s', $namespace, $constantName); if ($this->constantExists($namespacedConstantName, $context)) { return $namespacedConstantName; } } if ($this->constantExists($constantName, $context)) { return $constantName; } throw Exception\UnableToCompileNode::becauseOfNotFoundConstantReference($context, $constNode, $constantName); } private function constantExists(string $constantName, CompilerContext $context): bool { if (defined($constantName)) { return true; } try { $context->getReflector()->reflectConstant($constantName); return true; } catch (IdentifierNotFound) { return false; } } private function getConstantValue(Node\Expr\ConstFetch $node, string|null $constantName, CompilerContext $context): mixed { // It's not resolved when constant value is expression // @infection-ignore-all Assignment, AssignCoalesce: There's no difference, ??= is just optimization $constantName ??= $this->resolveConstantName($node, $context); if (defined($constantName)) { return constant($constantName); } return $context->getReflector()->reflectConstant($constantName)->getValue(); } private function resolveClassConstantName(Node\Expr\ClassConstFetch $node, CompilerContext $context): string { assert($node->name instanceof Node\Identifier); $constantName = $node->name->name; assert($node->class instanceof Node\Name); $className = $node->class->toString(); return sprintf('%s::%s', $this->resolveClassName($className, $context), $constantName); } private function getClassConstantValue(Node\Expr\ClassConstFetch $node, string|null $classConstantName, CompilerContext $context): mixed { // It's not resolved when constant value is expression // @infection-ignore-all Assignment, AssignCoalesce: There's no difference, ??= is just optimization $classConstantName ??= $this->resolveClassConstantName($node, $context); [$className, $constantName] = explode('::', $classConstantName); assert($constantName !== ''); if ($constantName === 'class') { return $className; } $classContext = $context->getClass(); $classReflection = $classContext !== null && $classContext->getName() === $className ? $classContext : $context->getReflector()->reflectClass($className); $reflectionConstant = $classReflection->getConstant($constantName); if (! $reflectionConstant instanceof ReflectionClassConstant) { throw Exception\UnableToCompileNode::becauseOfNotFoundClassConstantReference($context, $classReflection, $node); } return $reflectionConstant->getValue(); } /** * Compile a __DIR__ node */ private function compileDirConstant(CompilerContext $context, Node\Scalar\MagicConst\Dir $node): string { $fileName = $context->getFileName(); if ($fileName === null) { throw Exception\UnableToCompileNode::becauseOfMissingFileName($context, $node); } return dirname(FileHelper::normalizeWindowsPath($fileName)); } /** * Compile a __FILE__ node */ private function compileFileConstant(CompilerContext $context, Node\Scalar\MagicConst\File $node): string { $fileName = $context->getFileName(); if ($fileName === null) { throw Exception\UnableToCompileNode::becauseOfMissingFileName($context, $node); } return FileHelper::normalizeWindowsPath($fileName); } /** * Compiles magic constant __CLASS__ */ private function compileClassConstant(CompilerContext $context): string { return $context->getClass()?->getName() ?? ''; } private function resolveClassName(string $className, CompilerContext $context): string { if ($className !== 'self' && $className !== 'static' && $className !== 'parent') { return $className; } $classContext = $context->getClass(); assert($classContext !== null); if ($className !== 'parent') { return $classContext->getName(); } $parentClass = $classContext->getParentClass(); assert($parentClass instanceof ReflectionClass); return $parentClass->getName(); } } __halt_compiler();----SIGNATURE:----p1mwJ0uFw5sC40sajQZiFGaI+Z6pYgRImJ0Fa5+qHmuoQFTZRtzJ6JjFXXq9YCNLrOfkPu++aF9fjqh/1P+doEL730OcRFuCaG8M1whaIzvD8XBsIHmOfT8RI5bgfIoYeMIfK5pnAIbuEw+U4NP9sjsLiH4NTRmK+gFuiKWhCl5IptCyzE5kpsh/Oa6jBX3hPbIZpSUW9GaL0tgQtG2zcgwrAf183MCoSIrtmbWrE6z8AgyR4QEzHrw4iGqwoKukn8L/zjnWLufWKRCkdGZ+G5qNJdkGKsHGPsjkpY6FrvTy4GuBzuCmJiwAtT5KhFQTo4ibO85z2gH6LlF+iO4LewL/bnZlWILW9FEV+vVa1act5B925aNSVhpwdNA/IGhkB0EfaPi3epIWQsyaUhOGFTOlsYphkwQ1BbKEnosTptd+0lAW2lF0ZMAF+2xlD+egNOhKXQ+oTzXmOxrw341OxSibYzuMg402z8cZFbhHVz0VFklUaZKG+uT2/7liZdRWzlncEiS24K4OWqEysUa5LBakJoG+zvUqK3c9PkoUun7W3lB1nlbGuWjPvONoy/ld7xsLRVc1GNAkVUR2XITcps/CAaf6ll2q+Ip/U4XUGBX6+xNd0xHQVx63Zy7iWYqgN4XGibhwQOfR6GPp+l2g25suS2u2w/AIlyGnLUEhyx4=----ATTACHMENT:----OTYxODU2NzY0NzcyMjI1OCA0OTE0NzY5MjA4OTczMzcwIDk4OTA3Mjc5NDI0NTAwODg=