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

PHP基于角色过滤多维对象数组菜单失效问题求助

导航栏角色过滤功能失效的排查与修复

以下是导致过滤失效的核心问题及对应修复方案:

1. 方法访问权限与参数传递错误

  • Menu::filterByRole被定义为private,但你在index.php中直接调用了该方法,这会触发PHP致命错误,需先将其改为public。
  • 方法参数string ...$role是可变参数,调用时直接传数组['ADMIN', 'USER']会导致参数被解析为二维数组,正确调用方式是传递单个角色字符串:filterByRole('ADMIN', 'USER')。

2. 角色匹配逻辑错误

不管是Menu中过滤MenuItem,还是DropDownItem中过滤子项,你使用的in_array($item->getRole(), $role)逻辑完全错误——getRole()返回的是角色数组,而$role是字符串数组,in_array无法判断两个数组是否存在交集。正确做法是用array_intersect检查是否有共同角色。

3. DropDownItem完整过滤逻辑缺失

  • 未判断DropDownItem自身的角色权限,直接处理子项;
  • 子项过滤完成后,如果没有可见子项,应当把该DropDownItem从菜单中移除。

修正后的完整代码

Menu类修正

class Menu
{
    public const ROLE_HOST = "HOST";
    public const ROLE_USER = "USER";
    public const ROLE_ADMIN = "ADMIN";

    /**
     *@param array<MenuItem|DropDownItem>
     */
    public function __construct(
        private array $menuItems,
        private array $role = [self::ROLE_HOST]
    ){}

    public function build()
    {
        $result = "<ul class=\"nav-menu\">%s</ul>";
        $items = array_map(fn ($item) => $item->build(), $this->menuItems);
        return sprintf($result, implode("", $items));
    }

    public function setRole(...$role): self
    {
        $this->role = $role;
        return $this;
    }

    // 修改为public,同时修正参数与判断逻辑
    public function filterByRole(string ...$role): self
    {
        $filtered = [];
        foreach ($this->menuItems as $item) {
            if ($item instanceof MenuItem) {
                // 检查当前菜单项的角色与目标角色是否有交集
                if (!empty(array_intersect($item->getRole(), $role))) {
                    $filtered[] = $item;
                }
            }

            if ($item instanceof DropDownItem) {
                // 先过滤子项
                $item->filterItemsByRole(...$role);
                // 检查DropDownItem自身权限,且过滤后有子项才保留
                if (!empty(array_intersect($item->getRole(), $role)) && !empty($item->getItems())) {
                    $filtered[] = $item;
                }
            }
        }
        $this->menuItems = $filtered;
        return $this;
    }
}

DropDownItem类修正

class DropDownItem
{
    public function __construct(
        private string $title,
        /**
         * @param array<MenuItem> $menuItems
         */
         private array $menuItems,
         private ?array $role = [Menu::ROLE_HOST]
    ){}

    public function getItems(): array
    {
        return $this->menuItems;
    }

    public function getRole(): array
    {
        return $this->role;
    }

    public function setRole(string ...$role): void
    {
        $this->role = $role;
    }

    public function build(): string
    {
        $result = <<<HTM
            <li class="menu-has-children">
                <a href="">%s</a>
                <ul>
                    %s
                </ul>
        HTM;
        $items = array_map(fn($item) => $item->build(), $this->menuItems);
        return sprintf(
            $result,
            $this->title, 
            implode("", $items)
        );
    }

    public function filterItemsByRole(string ...$role): self
    {
        $filtered = array_filter(
            $this->menuItems,
            fn($item) => !empty(array_intersect($item->getRole(), $role))
        );
        $this->menuItems = $filtered;
        return $this;
     }
}

index.php调用修正

$menu = MenuFactory::build();
// 直接传递单个角色字符串,而非数组
echo $menu->filterByRole('ADMIN', 'USER')->build();

修复后效果

  • 保留Home、About、Contact(均支持ADMIN/USER角色);
  • 保留Dropdown item,并仅显示Sub-item 1(ADMIN/USER可见)和Sub-item 2(USER可见);
  • 隐藏仅HOST可见的Item菜单项。

内容的提问来源于stack exchange,提问作者Petr Fořt Fru-Fru

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:55:54