为何被包含文件无法访问我的PHP数组?
动态向全局菜单数组添加插件菜单条目问题
我正在从零搭建兼具练习和帮朋友开发用途的网站,其中核心需求之一是通过自定义插件和模块动态生成导航菜单。目前config.php中定义了基础配置和初始的$menuItems数组,期望User插件能向该数组追加新的菜单项,但在插件中调用$menuItems时提示变量未定义——已确认config.php被正确包含,但无法访问该数组。
相关代码片段
config.php
<?php function Deny() { if(!defined("__directaccess")) { header("Location: /"); exit(); } } //Deny(); $Plugins = array("Bootstrap", "MySQL", "User"); $menuItems = array ( "Home" => "/", ); //Create a root directory base name to reference define('__root', dirname(__file__)); //Create Class Reference Global Variable define('__class', __root . '/classes'); //Create Module reference define('__modules', __root.'/modules'); //Create Plugin reference define('__plugins', __root.'/plugins');
User.class.php
$menu = array ( "User Panel" => "/index.php?page=user", "Logout" => "/index.php?page=login&module=logout", ); print_r($menuItems); function __isOnline() { if(isset($_SESSION['username'])) { return true; } else { return false; } } class UserFunctions extends webConn { public function userDetails($arg, $username) { $query = <<<SQL SELECT * FROM account WHERE username = :username SQL; $resource = $this->db->prepare( $query ); $resource->execute( array ( ":username" => $username, )); $result = $resource->fetch(PDO::FETCH_ASSOC); return $result[$arg]; } } $userFunction = new UserFunctions();
index.php
LoadPlugins($Plugins); LoadModule("TopNav"); LoadPages();
loader.php
session_start(); define("__directaccess", true); require_once("config.php"); //Loads All Class Functions function LoadClasses() { foreach(glob(__class.'/*.class.php') as $class) { if(file_exists($class)) { require_once($class); } } } function LoadPlugins($Plugins) { foreach($Plugins as $Plugin) { LoadPlugin($Plugin); } } function LoadPages() { if(isset($_GET['page'])) { if(file_exists(__root. '/includes/' . $_GET['page'] . '.php')) { require_once(__root. '/includes/' . $_GET['page'] . '.php'); } else { echo "Page not Found"; //Make a 404 Error Page } } if(!isset($_GET['page'])) { if(file_exists(__root . '/includes/homepage.php')) { require_once(__root . '/includes/homepage.php'); } } } function LoadModule($moduleName, $page="index") { $path = __modules . '/' . $moduleName . '/' . $page . '.php'; if(file_exists($path)) { require_once($path); } else { echo "Failed to Load module " . $moduleName; } } function LoadPlugin($pluginName) { $path = __plugins . '/' . $pluginName . '/' . $pluginName . '.class.php'; if(file_exists($path)) { require_once($path); } else { echo "Failed to load plugin " . $pluginName; } }
问题原因
问题出在变量作用域上:$menuItems是在全局作用域中定义的,但LoadPlugin是一个函数,函数内部有独立的作用域,加载插件文件时,文件内的代码默认在函数作用域中执行,无法直接访问全局的$menuItems变量。
解决方案
方法1:在插件中声明全局变量
在User.class.php开头添加global $menuItems;,然后合并菜单数组:
global $menuItems; $menu = array ( "User Panel" => "/index.php?page=user", "Logout" => "/index.php?page=login&module=logout", ); // 合并到全局菜单数组 $menuItems = array_merge($menuItems, $menu);
方法2:修改加载函数,传递全局变量
修改LoadPlugin函数,先声明全局的$menuItems,确保插件加载时能访问到:
function LoadPlugin($pluginName) { global $menuItems; $path = __plugins . '/' . $pluginName . '/' . $pluginName . '.class.php'; if(file_exists($path)) { require_once($path); } else { echo "Failed to load plugin " . $pluginName; } }
方法3:封装菜单管理类(更优雅的方案)
创建一个MenuManager类统一管理菜单,避免全局变量的作用域问题:
在classes/MenuManager.class.php中添加:
class MenuManager { private static $menuItems = []; // 初始化基础菜单 public static function init($initialItems) { self::$menuItems = $initialItems; } // 添加菜单项 public static function addItems($items) { self::$menuItems = array_merge(self::$menuItems, $items); } // 获取所有菜单项 public static function getItems() { return self::$menuItems; } }
在config.php中替换原$menuItems定义,改为初始化菜单管理器:
// 替换原来的$menuItems定义 require_once(__class . '/MenuManager.class.php'); MenuManager::init([ "Home" => "/", ]);
在User.class.php中添加菜单:
$menu = array ( "User Panel" => "/index.php?page=user", "Logout" => "/index.php?page=login&module=logout", ); MenuManager::addItems($menu);
在TopNav模块中获取菜单用于渲染:
$menuItems = MenuManager::getItems(); // 编写渲染菜单的代码
内容的提问来源于stack exchange,提问作者Morgan Green
相关产品推荐
相关产品推荐

