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:----H46ZlCXYArFZueLUUI81PeHj9tKwI5YaDMQ+egJzA7BHyiurEeIN5cxaaMbJvoNkPI4BMyEpRFib/copooy9fihf0kuqhNjDMB3HxaScavXEwQ1CWsQrtOMV5Nbiet+heASbgRG0G50hKx3x5I/wsjlEvm/WuapTHtiT6h4pVFO1ZlHhJXfctsmGiZwiVljjkxe6kkQeHsxPU29B0EU+kYCXdA8BlQpQu56maisnhKtQjxVBQ1KNWA6I62a7TBKqmhTPCZbf4CqX5UzGPZ9qbiF85pXXElZ+PSRgLZs5K3EdNPYOfLTbx/I66cAR8Zu/ZDRaNvrte344XwTVTUB5cabbH58KKjGuNpd06K7E975PxuJsI4J0xUvJWqoI65dtXaiR4hVREM210u+bPOAHu7EfE+bZh4Z7D5j4z9BL/qVlPC5cbt6ALS79HcuXIIJlLZMVqIYPQ2FOqh4wSvGT7tGBfdTGIQXFg/uEhOXj3/RhVT2cbRFwcXeYffsro+74eABg9GA62J/VqiPZc08mCigH+Jkw3qv+a1wdbspo0E00fKhf8TXYI+vHsoJvmJfo44Ha77ac6NRSG7O0jlHo53tnYiJf9MNCTjuvcSrK3lMcjFJ8w1VfQKgvn9sKxGfrtv0TYfGoGL09naGYi6xXvzBhT+IZhS/VzzoZTg0YrcI=----ATTACHMENT:----NjQ5MTg3NTk2Mzc0NTQ0OCA1NTU5MTQxMTMxMDQ1MzE0IDQ5Mzc4NzY4MDM4MjcyMDE=