ThinkPHP 3.2.2 引入的插件控制器機制,打破了傳統「模塊-控制器-操作」的固定路由結構,允許通過 URL 參數動態切換控制器實現類。這為多租戶系統、功能插件化擴展、主題皮膚切換等場景提供了原生支持。
// 配置文件 config.php
return array(
// 插件控制器 URL 參數名(默認 addon)
'VAR_ADDON' => 'addon',
// 插件目錄名稱(默認 Addon)
'ADDON_PATH' => 'Addon',
// 是否啟用插件控制器
'ADDON_CONTROLLER' => true,
);
Application/ ├── Home/ │ ├── Controller/ # 普通控制器 │ │ └── InfoController.class.php │ └── Addon/ # 插件目錄 │ └── SystemInfo/ # 插件名稱 │ └── Controller/ │ └── InfoController.class.php # 插件控制器
# 調用 Home 模塊下 Info 控制器的 index 操作 # 使用 SystemInfo 插件的控制器 https://serverName/Home/info/index/addon/SystemInfo # 等效於調用: # Home/Addon/SystemInfo/Controller/InfoController.class.php
修改 VAR_ADDON 後的訪問方式:
// 配置 'VAR_ADDON' => 'plugin' https://serverName/Home/info/index/plugin/SystemInfo
namespace Home\Addon\SystemInfo\Controller;
use Think\Controller;
class InfoController extends Controller {
public function index() {
echo 'Addon SystemInfo - 插件控制器輸出';
}
public function detail($id) {
// 業務邏輯
$this->assign('data', $this->getData($id));
$this->display('Widget:detail'); // 支持跨模塊模板
}
}
Home/
└── Addon/
└── SystemInfo/
├── Controller/
│ └── InfoController.class.php
└── View/
└── Info/
├── index.html # 默認模板
└── detail.html # 自定義模板
// 前台控制器基類
class BaseController extends Controller {
protected function _initialize() {
// 從 Session/Cookie/域名 確定主題
$theme = session('theme') ?: 'default';
// 動態設置插件參數
$_GET[C('VAR_ADDON')] = $theme;
}
}
// 訪問任意控制器自動應用主題插件
// https://site.com/Home/Index/index -> 使用 Default 插件
// https://site.com/Home/Index/index?theme=mobile -> 使用 Mobile 插件
// 支付模塊控制器
class PayController extends Controller {
public function checkout($gateway = 'alipay') {
// 通過插件參數動態加載支付網關
$_GET[C('VAR_ADDON')] = ucfirst($gateway) . 'Pay';
// 調用統一接口
$this->forward('Pay/index');
}
}
// 插件結構
Addon/
├── AlipayPay/Controller/PayController.class.php
├── WechatPay/Controller/PayController.class.php
└── UnionPay/Controller/PayController.class.php
// 後台菜單配置數據庫表
// id | title | controller | addon
// 1 | 會員管理 | Member | UserManage
// 2 | 訂單管理 | Order | OrderExtend
// 後台基類控制器
class AdminBaseController extends Controller {
public function _empty($name, $args) {
$menu = M('Menu')->where("controller='$name'")->find();
if ($menu && $menu['addon']) {
$_GET[C('VAR_ADDON')] = $menu['addon'];
$this->forward("$name/index");
} else {
$this->error('功能未啟用');
}
}
}
_initialize() 中集中處理插件參數注入UserManage),控制器保持標準命名info.ini 聲明兼容的 ThinkPHP 版本VAR_ADDON 參數值,防止目錄遍歷攻擊ThinkPHP 5.0+ 移除了原生插件控制器機制,推薦使用以下替代方案:
event() 機制實現功能擴展