首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

ThinkPHP 自定義標籤庫實作:View 層直接查詢資料庫 (TagLib 擴充指南)

     編輯:PHP 相關知識

需求場景

在模板檔案中直接查詢資料庫並輸出,避免控制器傳遞大量資料,適用於側邊欄、導航選單、推薦區塊等通用片段。

實作步驟

1. 建立標籤庫類別

路徑:ThinkPHP/Lib/Think/Template/TagLib/TagLibZpass.class.php (命名規則:TagLib{Name}.class.php)

<?php
namespace Think\Template\TagLib;

class TagLibZpass extends TagLib
{
    // 標籤定義
    protected $tags = [
        'select' => [
            'attr'  => 'table,limit,order,where,field', // 支援屬性
            'level' => 3,                               // 巢狀層級
            'close' => 1,                               // 需閉合標籤
        ],
    ];

    public function _select($attr, $content)
    {
        // 解析 XML 屬性
        $tag = $this->parseXmlAttr($attr, 'table');
        $table = $tag['table'];

        // 快取機制:相同屬性+內容只解析一次
        static $_cache = [];
        $key = md5($attr . $content);
        if (isset($_cache[$key])) {
            return $_cache[$key];
        }

        // 查詢資料
        $db = M($table);
        $list = $db
            ->where($tag['where'])
            ->order($tag['order'])
            ->limit($tag['limit'])
            ->field($tag['field'])
            ->select();

        // 解析模板內容中的 [field:xxx] 標記
        preg_match_all('/\[field:(\w+)\]/', $content, $matches);
        $fields = array_unique($matches[1]); // 去重

        $parseStr = '';
        foreach ($list as $i => $row) {
            $itemStr = $content;
            foreach ($fields as $field) {
                $itemStr = str_replace("[field:{$field}]", $row[$field], $itemStr);
            }
            $parseStr .= $itemStr;
        }

        $_cache[$key] = $parseStr;

        // 交給模板引擎進一步解析 (支援 {:U(...)} 等語法)
        return $this->tpl->parse($parseStr);
    }
}
?>

2. 模板中引入並使用

<!-- 引入標籤庫,name 對應 TagLib{Zpass} 的 Zpass -->
<taglib name="zpass" />

<!-- 使用 select 標籤 -->
<zpass:select 
    table="classes" 
    field="id,title" 
    order="sort desc" 
    limit="3" 
    where="status=1"
>
    <span class="marginleft_1">
        <a href="{:U('News/index', array('id=[field:id]'))}">[field:title]</a>
    </span>
</zpass:select>

關鍵技術點解析

屬性解析 parseXmlAttr()

  • 自動處理字串引號、變數解析 (支援 {$var})
  • 缺失屬性回傳空字串,需在 SQL 條件中自行判斷

快取機制

靜態變數 $_cache 以 md5($attr.$content) 為鍵,避免同一頁面重複標籤重複查詢與解析。注意:快取鍵不包含資料庫狀態,資料更新後需清除模板編譯快取 (Runtime/Cache/) 才會重新查詢。

欄位替換邏輯

  1. preg_match_all('/\[field:(\w+)\]/', ...) 擷取所有欄位標記
  2. array_unique 去重
  3. 遍歷查詢結果 $list,逐行替換 [field:xxx] 為實際值
  4. 拼接所有行輸出

模板引擎二次解析

return $this->tpl->parse($parseStr) 確保替換後的字串中若包含 {:U(...)}、{$var} 等 ThinkPHP 模板語法能正確編譯。

進階擴充建議

功能實作方向
支援 join 查詢新增 join、on 屬性,_select 中組裝 $db->join(...)
支援分頁整合 ThinkPHP Page 類,輸出分頁 HTML
條件判斷標籤新增 <zpass:if condition="...">...,呼叫 $this->parseCondition()
資料快取查詢前檢查 S('taglib_'.$key),命中則直接返回
命名空間支援 (TP5+)類別改為 app\taglib\Zpass,註冊於 config\taglib.php

注意事項

  • SQL 注入風險:where 屬性直接傳入 ->where(),若允許使用者輸入需嚴格過濾或改用參數綁定。
  • N+1 查詢問題:頁面若放置多個此類標籤,會產生多條 SQL。建議關鍵頁面改用控制器預先查詢 assign()。
  • 模板編譯快取:修改標籤庫代碼後必須清除 Runtime/Cache/ 目錄下編譯快取才生效。
  • ThinkPHP 版本差異:TP3.x 置於 Lib/Think/Template/TagLib/;TP5/6 需註冊至 config/taglib.php 或使用 \think\facade\TagLib::register()。

原作者:zpass (16852868@qq.com) | 整理補充:命名空間規範、快取機制解析、安全性警示、版本差異、進階擴充方向

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved