1. 程式人生 > >用 php 實現一個視圖組件和模板引擎——基礎

用 php 實現一個視圖組件和模板引擎——基礎

view content 如何實現 目前 內容 復用 tty 結構 有效

只要不是做後端接口開發和一些作為守護進程之類的服務器腳本,大多數時候都是在和瀏覽器打交道,因此合理組織並展現 html 標簽是最為常見的工作。一般大家使用框架時,都會自帶有一套視圖組件和模板引擎。

我們不討論這些組件和引擎的好壞。因為這些東西已經經過考驗,可以在生產環境下使用。我們現在只是為了學習一些東西,這時候了解一些原理上的可能對以後的幫助更大,如果一些人真的很有時間,利用這些基礎知識完全可以寫一個自己的組件,即可當做練習,也可以拿去自用。

好了,說這麽多,我還是希望很多人明白,視圖和模板引擎實際上原理十分簡單,所涉及的知識可以說是太基礎不過的了。但,千萬不要把視圖和模板引擎搞混淆,這兩個真的不是一個東西 。

為了理解這些,我們先從視圖開始了解。

視圖

視圖,你所看見的部分。

<?php
echo ‘hello, world‘;

從簡單開始理解

這就是個視圖文件中的代碼,沒錯就這麽簡單。視圖,實際上是在 MVC 這種架構上提出的。MVC 中,視圖負責呈現數據。因此可以說只要是輸出了數據的,都叫做視圖。

在沒有使用框架的時候,業務邏輯、數據的讀寫、組織和展示都是在一堆代碼裏,難以剝離,隨著項目增大變得越來越難以維護。MVC 有效的分離了三者,各司其職。視圖作為呈現數據的,只負責組織、展示,不再負責讀寫和業務邏輯。

既然視圖只負責呈現數據,那麽單獨成一個文件,這個文件內的代碼絕對不要讀取數據庫、做業務判斷,那麽就算你將視圖獨立出來了。這時候大多數人會想到,視圖中的數據從哪來呢?

我們以一個簡單的例子實現一個業務邏輯和視圖分離的結構。

文件 controller.php,代碼如下

<?php
$time = time();
$string = ($time % 2) == 0 ? ‘偶數‘ : ‘奇數‘;
 
// 加載視圖
include ‘view.php‘;

文件 view.php,代碼如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>視圖實例</
title> </head> <body> <p>時間戳 <?=$time?><?=$string?></p> </body> </html>

代碼寫好,運行後結果是預期的,對嗎?

這兩個文件中,毋庸置疑 view.php 就是視圖文件,而 controller.php 你可以當做一個控制器,因為它實現了主要的業務邏輯(雖然極其簡單)。盡管簡潔,但在結構上我們已經完全分離。

事實上,目前所有的框架的視圖的實現都大致如此,沒什麽特別的、神秘的地方,只是說框架它做了更多的事,比如驗證視圖文件的合法性、通過更少的參數去加載視圖等等。

如何傳遞一個變量到視圖文件?

我相信很多人在這個上面有著很多的疑惑。比如我們常看到這樣向視圖傳遞變量:

// laravel 通過視圖類的 with 方法傳遞
View::make(‘view‘)->with(‘value‘, ‘實際的數據‘);
 
// Smarty 模板引擎通過 assign 方法向最終的編譯好的視圖傳遞變量
$smarty->assign(‘value‘, ‘實際的數據‘);
 
// ...

實際上,在上面的邏輯與視圖分離的例子中已經說了。當 include 或 require 一個文件時,該文件會繼承引入他的那段代碼的作用域。php 官方文檔是這麽說的:

當一個文件被包含時,其中所包含的代碼繼承了 include 所在行的變量範圍。從該處開始,調用文件在該行處可用的任何變量在被調用的文件中也都可用。不過所有在包含文件中定義的函數和類都具有全局作用域。

如果 include 出現於調用文件中的一個函數裏,則被調用的文件中所包含的所有代碼將表現得如同它們是在該函數內部定義的一樣。所以它將遵循該函數的變量範圍。此規則的一個例外是魔術常量,它們是在發生包含之前就已被解析器處理的。

實戰 —— 實現一個視圖類

假設我們有一個視圖類,定義在文件 View.php

<?php
class View
{
    protected $data = [];
 
    public function display($file)
    {
        extract($this->data);
 
        include $file;
    }
 
    public function assign($key, $value)
    {
        $this->data[$key] = $value;
    }
}

我們現在有模板文件,定義在文件 Template.php:

<!DOCTYPE html>
<html>
    <head>
        <title><?=$title?></title>
        <meta charset="utf-8">
    </head>
    <body>
        <h1><?=$title?></h1>
        <p>
            <?=$content?>
        </p>
    </body>
</html>

然後我們的主要業務邏輯代碼如下:

<?php
// 包含視圖類文件
include ‘View.php‘;
 
$view = new View();
 
$view->assign(‘title‘, ‘視圖測試‘);
$view->assign(‘content‘, ‘這是一個視圖類的示例‘);
 
$view->display(‘Template.php‘);

輸出的內容大家都已經看得出來了,我就不截圖了。

至此,大家應該都明白如何實現一個視圖了吧?其實原理就這麽簡單。

模板引擎

模板引擎的誕生實際上是將視圖拆分出來以後的事兒。大家看到了,上面例子中,所有模板中的變量,都是通過原生的 php 語法進行輸出。假如單純是輸出內容,其實不用模板引擎也可以,但是一旦涉及到需要復用模板或者對視圖文件進行模塊化的拆分,實現諸如繼承、布局之類的功能時,原生的 php 語法似乎需要寫更為復雜的代碼才能實現。

很顯然,我們不應該在視圖文件內寫超出職責或過於繁雜的額外代碼,因此,模板引擎就顯得十分必要。

模板引擎的用處並不是所謂的方便前端的美工和網頁設計師,因為原生的語法比很多模板引擎語法更為簡潔。實際上,模板引擎最主要的任務是簡化在視圖上的額外代碼,比如處理布局、模板繼承等等。

說了那麽多,如何實現模板引擎?

其實模板引擎就是將一個指定的模板標記通過正則匹配,替換成相應的合法 php 語句而已。


轉:https://www.insp.top/article/use-php-to-achieve-view-component-and-template-engine

用 php 實現一個視圖組件和模板引擎——基礎