You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IntelliJ PHP自定义检查:如何触发visitPhpFunctionCall调用?

解决IntelliJ PHP插件自定义检查中visitPhpFunctionCall未触发的问题

看起来你遇到的核心问题是使用了非递归的PhpElementVisitor,导致无法遍历到PHP文件中的嵌套函数调用元素,所以visitPhpFunctionCall始终没被触发。咱们一步步来解决这个问题:

问题根源

PhpElementVisitor是JetBrains PHP PSI提供的基础访问者,默认不会递归遍历子元素。你的PHP文件中header($headerName)作为根元素的子节点,不会被非递归访问者触及,只会触发根元素的visitElement方法,而不会深入到函数调用节点。

解决方案:改用递归访问者

将你的访问者从PhpElementVisitor替换为PhpRecursiveElementVisitor,它会自动递归遍历所有PSI元素,包括嵌套的函数调用。同时移除不必要的visitElement重写,避免干扰默认的类型调度逻辑。

修改后的检查类代码如下:

package com.ge.sdc.intellij.mtaplugin.security.php;

import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElementVisitor;
import com.jetbrains.php.lang.inspections.PhpInspection;
import com.jetbrains.php.lang.psi.elements.FunctionReference;
import com.jetbrains.php.lang.psi.visitors.PhpRecursiveElementVisitor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class UnsafeCallToHeaderInspection extends PhpInspection {
    private Logger log = Logger.getInstance(UnsafeCallToHeaderInspection.class);

    @Nullable
    @Override
    public String getStaticDescription() {
        return "Calls to 'header()' function must only use constant strings or safe-known patterns." +
                " Otherwise, this could allow arbitrary data to be passed in HTTP headers, and would then alter the behavior of the browser (or client)." +
                " Ie: Inserting a custom Content-Security-Policy or a custom Content-Type can break several securities and be a breach.";
    }

    @NotNull
    @Override
    public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder problemsHolder, final boolean isOnTheFly) {
        return new PhpRecursiveElementVisitor() {
            @Override
            public void visitPhpFunctionCall(FunctionReference reference) {
                log.debug("visitPhpFunctionCall called for: " + reference.getName());
                
                // 只处理header函数调用
                if ("header".equals(reference.getName())) {
                    // 这里添加你的安全检查逻辑,比如判断参数是否为常量/安全值
                    problemsHolder.registerProblem(reference, "Unsafe call to 'header()' function detected");
                }

                // 如果需要继续递归遍历函数调用的子元素(比如参数),保留此行;否则可以移除
                super.visitPhpFunctionCall(reference);
            }
        };
    }
}

关键修改说明

  1. 切换到递归访问者:PhpRecursiveElementVisitor会自动遍历所有嵌套的PSI元素,确保header()调用能被检测到。
  2. 移除冗余的visitElement:默认的递归访问者会正确调度对应类型的visit方法,手动重写visitElement反而可能干扰类型匹配。
  3. 增加函数名校验:确保只处理header()函数,避免触发其他函数的检查逻辑。

额外调试技巧

如果修改后仍未触发visitPhpFunctionCall,可以临时添加以下代码确认PSI元素类型:

// 在递归访问者中临时添加
@Override
public void visitElement(com.intellij.psi.PsiElement element) {
    log.debug("Visited element type: " + element.getClass().getSimpleName());
    super.visitElement(element);
}

运行后查看日志,确认header()对应的元素是否为FunctionReference——如果不是,可能需要检查PHP SDK的版本兼容性,或者PSI元素的识别逻辑。

内容的提问来源于stack exchange,提问作者Xenos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:20:31