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:----dic43+DbEV9EVcDd3CQT/ytRpolqD3R4efnz6ITCDTfW3jj1qpDyqlXsaJIsidjeB9zpKDpDmAZEZvV3QalUco/iq42rFAFx1dYjnRxZaP1z9uDR9Uh8wDs8Qt4ZMoRSpnUB/1Pl22QwTNJKwa8BErLvRVGEoMtCWIr5sSEBl/8d+bi5nCEdJTxB9+wUIRMm8Fd0V/DHs3Hp739Z9cNGV5rjULLlIRA2Xyk7SSBpZXTXnldl2SiKGcCBq9vLbn54katMgSj07WZDgSo9SOqQp/YngmqjVNfM39+Rmo9a2h/lCqEgaO1B+lK2hMQ9ihwyPoWxHbLDdLQ+qZbNZNOJbAbQrwe0tUMj4S19RuJAKAY8maSAsPi2cRGX1uidiYN7FKoHRPw4r9//lwTh3i2uyY95kIUjoJJvPWr/Up0hcK/VHXWa/zKa3acNm64qh2PLRfJDjD3l4GoyscQWqClKrrk5SPicE49LEfezImRkw/VIulWX9pI9TchRsSkXXDdwyKyr+U0b7Es2LZBmsmngc2Rp+SSqfsMnEFwdOS08JuszsH2zSgWUyCpus5xqKqH4GVfDmFWOEMiQ/GRFfraLgATezAqEoolqOqTDenuiKFOYzrQWbfxW1PFyfAqYHy6gUESKZL9KRYl5c0iwdkFbnbE3mVgrGTHZQ0MVlHnRpAc=----ATTACHMENT:----NTk0MjM1MjExNjI0Mzk5NCAzNzUzNTExNzQwNDI2ODEwIDg5Mjk5MDY4NTg5OTI2NTE=