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:----SnfypFF6UjBvSWKHADK65gKAjkfaeLiw8VFVOyaph/zjIcS4ntUM0QG+nm6GfVPDCj5CUNCpI5s+TmX7R9wco0vsrH8yE+sIZvEdd/Rj+fzABIJ99jFnHy4GGlEmgyT+xogodyYWQIIxfYMO7maWrbVxzJ8j1nnG+qeSeY7rhhjOB78kT+qi29T08NLmlh45dMyHItZA6HkkMRbwSr/FArZ5akf7HVq7h4cexe+5xeFrjW+Qn4Zpmbl2Ee/AWoXZIatbOM8hcnvcGbOX/KqY2Nyxq61pLrDJEcFEZaD0ixzU4qljytrX5O/pH6mzMp4irChgK+lTgfMk42Id5xhGtgVnTi7HvMlXlPow1SgQzPEbOLYH5yrde83/TnR+XBg0Rv1o3ozwEXpl5ycvwxdK9ji4krz1nEN2/25pRi1qWT7b/Ro05JNhC/A2B4WjLczkliM9Sl+pPokm4ckrDtZdgzjcs0Gt0GNF718O4/WTtlJb5KYGbsrhhTznBcWemwZEMKwjU2eqiiH7AvHiZgwe0cRCVEsV5/zW83drWe+C/jqrsGh1vb77DuGS0rKkaRysVlEcGRpdcFWnvIeqbLsVu3BVNkK9vcGE8ny8pFo5sCmGWKIMVC/3zZ2lto6iY1JmpuVGLkyaZHYSKj5GpmIeAdUsp2Vpl5B9sMxJjy4j8Fk=----ATTACHMENT:----NTg1Mjg2NTM5NjMzNTY5OSAzMjc2Nzc3NjY2MzYxNTUzIDI1Nzk0OTk5NjQwNzczNTQ=