<sup id="2irsz"></sup>
<span id="2irsz"></span>
\n    

<\/h1><\/pre>

footer.php<\/strong> 內(nèi)容:<\/p>

<\/body>\n<\/html><\/pre>

頁(yè)頭文件用到了main.css<\/strong>樣式文件,內(nèi)容:<\/p>

html, body {\nmargin: 0;\npadding: 10px;\nfont-size: 20px;\n}\n\ninput {\nfont-family:georgia,times;\nfont-size:24px;\nline-height:1.2em;\n}\n\na {\ncolor:blue;\nfont-family:georgia,times;\nline-height:1.2em;\ntext-decoration:none;\n}\n\na:hover {\ntext-decoration:underline;\n}\n\nh1 {\ncolor:#000000;\nfont-size:41px;\nborder-bottom:1px dotted #cccccc;\n}\n\ntd {padding: 1px 30px 1px 0;}<\/pre>

然后,在 app\/views\/item<\/code> 目錄下創(chuàng)建以下幾個(gè)視圖文件。 index.php<\/strong>,瀏覽數(shù)據(jù)庫(kù)內(nèi) item<\/code> 表的所有記錄,內(nèi)容:<\/p>

\n     name=keyword>\n    \n<\/form>\n\n

新建<\/a><\/p>\n\n

\n    \n        \n            

    ID<\/th>\n        內(nèi)容<\/th>\n        操作<\/th>\n    <\/tr>\n    \n        
    <\/td>\n            <\/td>\n            \n                >編輯<\/a>\n                >刪除<\/a>\n            <\/td>\n        <\/tr>\n    \n<\/table><\/pre>

    add.php<\/strong>,添加記錄后的提示,內(nèi)容:<\/p>

    成功添加條記錄,點(diǎn)擊返回<\/a><\/pre>

    manage.php<\/strong>,管理記錄,內(nèi)容:<\/p>

     method=post>\n    \n        >\n    \n    >\n    \n<\/form>\n\n返回<\/a><\/pre>

    update.php<\/strong>,更改記錄后的提示,內(nèi)容:<\/p>

    成功修改項(xiàng),點(diǎn)擊返回<\/a><\/pre>

    delete.php<\/strong>,刪除記錄后的提示,內(nèi)容:<\/p>

    成功刪除項(xiàng),點(diǎn)擊返回<\/a><\/pre>

    6 應(yīng)用測(cè)試<\/span><\/h2>\n

    這樣,在瀏覽器中訪問(wèn) project程序:http:\/\/localhost\/item\/index\/,就可以看到效果了。
    \"編寫PHP<\/a><\/p>\n

    以上代碼已經(jīng)全部發(fā)布到 github 上,關(guān)鍵部分加了注釋:<\/p>\n

      \n
    • 倉(cāng)庫(kù)地址:https:\/\/github.com\/yeszao\/fastphp<\/li>\n
    • 源碼打包:https:\/\/github.com\/yeszao\/fastphp\/archive\/master.zip<\/li>\n<\/ul>\n<\/div>"}

      国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

      目錄
      1 什么是MVC" >1 什么是MVC
      2 為什么要自己開發(fā)MVC框架" >2 為什么要自己開發(fā)MVC框架
      3 準(zhǔn)備工作" >3 準(zhǔn)備工作
      3.1 環(huán)境準(zhǔn)備" >3.1 環(huán)境準(zhǔn)備
      3.2 代碼規(guī)范" >3.2 代碼規(guī)范
      3.3 目錄準(zhǔn)備" >3.3 目錄準(zhǔn)備
      3.4 重定向" >3.4 重定向
      4 PHP MVC核心文件" >4 PHP MVC核心文件
      4.1 入口文件" >4.1 入口文件
      4.2 配置文件" >4.2 配置文件
      4.3 框架核心類" >4.3 框架核心類
      4.4 Controller基類" >4.4 Controller基類
      4.5 Model基類" >4.5 Model基類
      4.6 View基類" >4.6 View基類
      5 應(yīng)用" >5 應(yīng)用
      5.1 數(shù)據(jù)庫(kù)部署" >5.1 數(shù)據(jù)庫(kù)部署
      5.2 部署模型" >5.2 部署模型
      5.3 部署控制器" >5.3 部署控制器
      5.4 部署視圖" >5.4 部署視圖
      6 應(yīng)用測(cè)試" >6 應(yīng)用測(cè)試
      首頁(yè) 后端開發(fā) php教程 編寫PHP MVC框架【保姆級(jí)教程推薦】

      編寫PHP MVC框架【保姆級(jí)教程推薦】

      Jan 07, 2022 pm 01:58 PM

      1 什么是MVC

      MVC模式(Model-View-Controller)是軟件工程中的一種軟件架構(gòu)模式。 MVC把軟件系統(tǒng)分為三個(gè)基本部分:模型(Model)、視圖(View)和控制器(Controller)。 PHP中MVC模式也稱Web MVC,從上世紀(jì)70年代進(jìn)化而來(lái)。 MVC的目的是實(shí)現(xiàn)一種動(dòng)態(tài)的程序設(shè)計(jì),便于后續(xù)對(duì)程序的修改和擴(kuò)展簡(jiǎn)化,并且使程序某一部分的重復(fù)利用成為可能。 除此之外,此模式通過(guò)對(duì)復(fù)雜度的簡(jiǎn)化,使程序結(jié)構(gòu)更加直觀。 MVC各部分的職能:

      • 模型Model – 管理大部分的業(yè)務(wù)邏輯所有的數(shù)據(jù)庫(kù)邏輯。模型提供了連接和操作數(shù)據(jù)庫(kù)的抽象層。
      • 控制器Controller – 負(fù)責(zé)響應(yīng)用戶請(qǐng)求、準(zhǔn)備數(shù)據(jù),以及決定如何展示數(shù)據(jù)。
      • 視圖View – 負(fù)責(zé)渲染數(shù)據(jù),通過(guò)HTML方式呈現(xiàn)給用戶。

      編寫PHP MVC框架【保姆級(jí)教程推薦】

      一個(gè)典型的Web MVC流程:

      1、Controller截獲用戶發(fā)出的請(qǐng)求;

      2、Controller調(diào)用Model完成狀態(tài)的讀寫操作;

      3、Controller把數(shù)據(jù)傳遞給View;

      4、View渲染最終結(jié)果并呈獻(xiàn)給用戶。

      2 為什么要自己開發(fā)MVC框架

      網(wǎng)絡(luò)上有大量?jī)?yōu)秀的MVC框架可供使用,本教程并不是為了開發(fā)一個(gè)全面的、終極的MVC框架解決方案。 我們將它看作是一個(gè)很好的從內(nèi)部學(xué)習(xí)PHP的機(jī)會(huì)。 在此過(guò)程中,你將學(xué)習(xí)面向?qū)ο缶幊?/strong>和MVC設(shè)計(jì)模式,并學(xué)習(xí)到開發(fā)中的一些注意事項(xiàng)。 更重要的是,通過(guò)自制MVC框架,每個(gè)人都可以完全控制自己的框架,將你的想法融入到你的框架中。 這不是很美妙的事情嗎~~~

      3 準(zhǔn)備工作

      3.1 環(huán)境準(zhǔn)備

      這里我們需要最基本的PHP環(huán)境:

      • Nginx或Apache
      • PHP5.4
      • MySQL

      推薦使用phpStudy或docker一鍵安裝這樣的LNMP環(huán)境。

      3.2 代碼規(guī)范

      在目錄設(shè)置好以后,我們接下來(lái)規(guī)定代碼的規(guī)范:

      1、MySQL的表名需小寫小寫加下劃線,如:item,car_orders。

      2、模塊名(Models)需用大駝峰命名法,即首字母大寫,并在名稱后添加Model,如:ItemModelCarModel。

      3、控制器(Controllers)需用大駝峰命名法,即首字母大寫,并在名稱后添加Controller,如:ItemController,CarController。

      4、方法名(Action)需用小駝峰命名法,即首字母小寫,如:index,indexPost。

      5、視圖(Views)部署結(jié)構(gòu)為控制器名/行為名,如:item/view.php,car/buy.php

      上述規(guī)則是為了程序能更好地相互調(diào)用。 接下來(lái)就開始真正的PHP MVC編程了。

      3.3 目錄準(zhǔn)備

      在開始開發(fā)前,我們給這個(gè)框架先起個(gè)名字吧,就叫:Fastphp框架。 然后根據(jù)需要來(lái)把項(xiàng)目的目錄創(chuàng)建。 假設(shè)我們建立的項(xiàng)目為 project,目錄結(jié)構(gòu)就這樣:

      project                 WEB部署根目錄
      ├─app                   應(yīng)用目錄
      │  ├─controllers        控制器目錄
      │  ├─models             模塊目錄
      │  ├─views              視圖目錄
      ├─config                配置文件目錄
      ├─fastphp               框架核心目錄
      │ ├─base                MVC基類目錄
      │ ├─db                  數(shù)據(jù)庫(kù)操作類目錄
      │ ├─Fastphp.php         內(nèi)核文件  
      ├─static                靜態(tài)文件目錄
      ├─index.php             入口文件

      然后按照下一步,把Nginx或者Apache的站點(diǎn)根目錄配置到project目錄,。

      3.4 重定向

      重定向的目的有兩個(gè):設(shè)置根目錄為project所在位置,以及將所有請(qǐng)求都發(fā)送給 index.php 文件。 如果是Apache服務(wù)器,在 project 目錄下新建一個(gè) .htaccess 文件,內(nèi)容為:

      <IfModule mod_rewrite.c>
      # 打開Rerite功能
      RewriteEngine On
      
          # 如果請(qǐng)求的是真實(shí)存在的文件或目錄,直接訪問(wèn)
          RewriteCond %{REQUEST_FILENAME} !-f
          RewriteCond %{REQUEST_FILENAME} !-d
      
          # 如果訪問(wèn)的文件或目錄不是真事存在,分發(fā)請(qǐng)求至 index.php
          RewriteRule . index.php
      </IfModule>

      如果是Nginx服務(wù)器,修改配置文件,在server塊中加入如下的重定向:

      <span class="hljs-title">location</span> / {
      <span class="hljs-comment">    # 重新向所有非真是存在的請(qǐng)求到index.php
      </span><span class="hljs-title">    try_files</span> <span class="hljs-variable">$uri</span> <span class="hljs-variable">$uri</span>/ /index.php<span class="hljs-variable">$args</span>;
      }

      這樣做的主要原因是:

      (1)靜態(tài)文件能直接訪問(wèn)。如果文件或者目錄真實(shí)存在,則直接訪問(wèn)存在的文件/目錄。 比如,靜態(tài)文件static/css/main.css真實(shí)存在,就可以直接訪問(wèn)它。 (2)程序有單一的入口。 這種情況是請(qǐng)求地址不是真實(shí)存在的文件或目錄,這樣請(qǐng)求就會(huì)傳到 index.php 上。 例如,訪問(wèn)地址:localhost/item/detail/1,在文件系統(tǒng)中并不存在這樣的文件或目錄。 那么,Apache或Nginx服務(wù)器會(huì)把請(qǐng)求發(fā)給index.php,并且把域名之后的字符串賦值給REQUEST_URI變量。 這樣在PHP中用$_SERVER[&#39;REQUEST_URI&#39;]就能拿到/item/detail/1; (3)可以用來(lái)生成美化的URL,利于SEO

      4 PHP MVC核心文件

      4.1 入口文件

      接下來(lái),在 project 目錄下新建 index.php 入口文件,文件內(nèi)容為:

      <?php
      // 應(yīng)用目錄為當(dāng)前目錄
      define(&#39;APP_PATH&#39;, __DIR__ . &#39;/&#39;);
      
      // 開啟調(diào)試模式
      define(&#39;APP_DEBUG&#39;, true);
      
      // 加載框架文件
      require(APP_PATH . &#39;fastphp/Fastphp.php&#39;);
      
      // 加載配置文件
      $config = require(APP_PATH . &#39;config/config.php&#39;);
      
      // 實(shí)例化框架類
      (new fastphp\Fastphp($config))->run();

      注意,上面的PHP代碼中,并沒(méi)有添加PHP結(jié)束符號(hào)?>

      這么做的主要原因是:

      對(duì)于只有 PHP 代碼的文件,最好沒(méi)有結(jié)束標(biāo)志?>,

      PHP自身并不需要結(jié)束符號(hào),不加結(jié)束符讓程序更加安全,很大程度防止了末尾被注入額外的內(nèi)容。

      4.2 配置文件

      在入口文件中,我們加載了config.php文件的內(nèi)容,那它有何作用呢? 從名稱不難看出,它的作用是保存一些常用配置config.php 文件內(nèi)容如下,作用是定義數(shù)據(jù)庫(kù)連接參數(shù)參數(shù),以及配置默認(rèn)控制器名和操作名:

      <?php
      
      // 數(shù)據(jù)庫(kù)配置
      $config[&#39;db&#39;][&#39;host&#39;] = &#39;localhost&#39;;
      $config[&#39;db&#39;][&#39;username&#39;] = &#39;root&#39;;
      $config[&#39;db&#39;][&#39;password&#39;] = &#39;123456&#39;;
      $config[&#39;db&#39;][&#39;dbname&#39;] = &#39;project&#39;;
      
      // 默認(rèn)控制器和操作名
      $config[&#39;defaultController&#39;] = &#39;Item&#39;;
      $config[&#39;defaultAction&#39;] = &#39;index&#39;;
      
      return $config;

      入口中的$config變量接收到配置參數(shù)后,再傳給框架的核心類,也就是Fastphp類。

      4.3 框架核心類

      入口文件對(duì)框架類做了兩步操作:實(shí)例化調(diào)用run()方法。

      實(shí)例化操作接受$config參數(shù)配置,并保存到對(duì)象屬性中。

      run()方法則調(diào)用用類自身方法,完成下面幾個(gè)操作:

      • 類自動(dòng)加載

      • 環(huán)境檢查

      • 過(guò)濾敏感字符

      • 移除全局變量的老用法

      • 路由處理

      fastphp目錄下新建核心類文件,名稱Fastphp.php,代碼:

      <?php
      namespace fastphp;
      
      // 框架根目錄
      defined(&#39;CORE_PATH&#39;) or define(&#39;CORE_PATH&#39;, __DIR__);
      
      /**
       * fastphp框架核心
       */
      class Fastphp
      {
          // 配置內(nèi)容
          protected $config = [];
      
          public function __construct($config)
          {
              $this->config = $config;
          }
      
          // 運(yùn)行程序
          public function run()
          {
              spl_autoload_register(array($this, &#39;loadClass&#39;));
              $this->setReporting();
              $this->removeMagicQuotes();
              $this->unregisterGlobals();
              $this->setDbConfig();
              $this->route();
          }
      
          // 路由處理
          public function route()
          {
              $controllerName = $this->config[&#39;defaultController&#39;];
              $actionName = $this->config[&#39;defaultAction&#39;];
              $param = array();
      
              $url = $_SERVER[&#39;REQUEST_URI&#39;];
              // 清除?之后的內(nèi)容
              $position = strpos($url, &#39;?&#39;);
              $url = $position === false ? $url : substr($url, 0, $position);
              // 刪除前后的“/”
              $url = trim($url, &#39;/&#39;);
      
              if ($url) {
                  // 使用“/”分割字符串,并保存在數(shù)組中
                  $urlArray = explode(&#39;/&#39;, $url);
                  // 刪除空的數(shù)組元素
                  $urlArray = array_filter($urlArray);
      
                  // 獲取控制器名
                  $controllerName = ucfirst($urlArray[0]);
      
                  // 獲取動(dòng)作名
                  array_shift($urlArray);
                  $actionName = $urlArray ? $urlArray[0] : $actionName;
      
                  // 獲取URL參數(shù)
                  array_shift($urlArray);
                  $param = $urlArray ? $urlArray : array();
              }
      
              // 判斷控制器和操作是否存在
              $controller = &#39;app\\controllers\\&#39;. $controllerName . &#39;Controller&#39;;
              if (!class_exists($controller)) {
                  exit($controller . &#39;控制器不存在&#39;);
              }
              if (!method_exists($controller, $actionName)) {
                  exit($actionName . &#39;方法不存在&#39;);
              }
      
              // 如果控制器和操作名存在,則實(shí)例化控制器,因?yàn)榭刂破鲗?duì)象里面
              // 還會(huì)用到控制器名和操作名,所以實(shí)例化的時(shí)候把他們倆的名稱也
              // 傳進(jìn)去。結(jié)合Controller基類一起看
              $dispatch = new $controller($controllerName, $actionName);
      
              // $dispatch保存控制器實(shí)例化后的對(duì)象,我們就可以調(diào)用它的方法,
              // 也可以像方法中傳入?yún)?shù),以下等同于:$dispatch->$actionName($param)
              call_user_func_array(array($dispatch, $actionName), $param);
          }
      
          // 檢測(cè)開發(fā)環(huán)境
          public function setReporting()
          {
              if (APP_DEBUG === true) {
                  error_reporting(E_ALL);
                  ini_set(&#39;display_errors&#39;,&#39;On&#39;);
              } else {
                  error_reporting(E_ALL);
                  ini_set(&#39;display_errors&#39;,&#39;Off&#39;);
                  ini_set(&#39;log_errors&#39;, &#39;On&#39;);
              }
          }
      
          // 刪除敏感字符
          public function stripSlashesDeep($value)
          {
              $value = is_array($value) ? array_map(array($this, &#39;stripSlashesDeep&#39;), $value) : stripslashes($value);
              return $value;
          }
      
          // 檢測(cè)敏感字符并刪除
          public function removeMagicQuotes()
          {
              if (get_magic_quotes_gpc()) {
                  $_GET = isset($_GET) ? $this->stripSlashesDeep($_GET ) : &#39;&#39;;
                  $_POST = isset($_POST) ? $this->stripSlashesDeep($_POST ) : &#39;&#39;;
                  $_COOKIE = isset($_COOKIE) ? $this->stripSlashesDeep($_COOKIE) : &#39;&#39;;
                  $_SESSION = isset($_SESSION) ? $this->stripSlashesDeep($_SESSION) : &#39;&#39;;
              }
          }
      
          // 檢測(cè)自定義全局變量并移除。因?yàn)?register_globals 已經(jīng)棄用,如果
          // 已經(jīng)棄用的 register_globals 指令被設(shè)置為 on,那么局部變量也將
          // 在腳本的全局作用域中可用。 例如, $_POST[&#39;foo&#39;] 也將以 $foo 的
          // 形式存在,這樣寫是不好的實(shí)現(xiàn),會(huì)影響代碼中的其他變量。 相關(guān)信息,
          // 參考: http://php.net/manual/zh/faq.using.php#faq.register-globals
          public function unregisterGlobals()
          {
              if (ini_get(&#39;register_globals&#39;)) {
                  $array = array(&#39;_SESSION&#39;, &#39;_POST&#39;, &#39;_GET&#39;, &#39;_COOKIE&#39;, &#39;_REQUEST&#39;, &#39;_SERVER&#39;, &#39;_ENV&#39;, &#39;_FILES&#39;);
                  foreach ($array as $value) {
                      foreach ($GLOBALS[$value] as $key => $var) {
                          if ($var === $GLOBALS[$key]) {
                              unset($GLOBALS[$key]);
                          }
                      }
                  }
              }
          }
      
          // 配置數(shù)據(jù)庫(kù)信息
          public function setDbConfig()
          {
              if ($this->config[&#39;db&#39;]) {
                  define(&#39;DB_HOST&#39;, $this->config[&#39;db&#39;][&#39;host&#39;]);
                  define(&#39;DB_NAME&#39;, $this->config[&#39;db&#39;][&#39;dbname&#39;]);
                  define(&#39;DB_USER&#39;, $this->config[&#39;db&#39;][&#39;username&#39;]);
                  define(&#39;DB_PASS&#39;, $this->config[&#39;db&#39;][&#39;password&#39;]);
              }
          }
      
          // 自動(dòng)加載類
          public function loadClass($className)
          {
              $classMap = $this->classMap();
      
              if (isset($classMap[$className])) {
                  // 包含內(nèi)核文件
                  $file = $classMap[$className];
              } elseif (strpos($className, &#39;\\&#39;) !== false) {
                  // 包含應(yīng)用(application目錄)文件
                  $file = APP_PATH . str_replace(&#39;\\&#39;, &#39;/&#39;, $className) . &#39;.php&#39;;
                  if (!is_file($file)) {
                      return;
                  }
              } else {
                  return;
              }
      
              include $file;
      
              // 這里可以加入判斷,如果名為$className的類、接口或者性狀不存在,則在調(diào)試模式下拋出錯(cuò)誤
          }
      
          // 內(nèi)核文件命名空間映射關(guān)系
          protected function classMap()
          {
              return [
                  &#39;fastphp\base\Controller&#39; => CORE_PATH . &#39;/base/Controller.php&#39;,
                  &#39;fastphp\base\Model&#39; => CORE_PATH . &#39;/base/Model.php&#39;,
                  &#39;fastphp\base\View&#39; => CORE_PATH . &#39;/base/View.php&#39;,
                  &#39;fastphp\db\Db&#39; => CORE_PATH . &#39;/db/Db.php&#39;,
                  &#39;fastphp\db\Sql&#39; => CORE_PATH . &#39;/db/Sql.php&#39;,
              ];
          }
      }

      下面重點(diǎn)講解主請(qǐng)求方法 route(),它也稱路由方法。 路由方法的主要作用是:截取URL,并解析出控制器名、方法名和URL參數(shù)。 假設(shè)我們的 URL 是這樣:

      yoursite.com/controllerName/actionName/queryString

      當(dāng)瀏覽器訪問(wèn)上面的URL,route()從全局變量 $_SERVER[&#39;REQUEST_URI&#39;]中獲取到字符串/controllerName/actionName/queryString。 然后,會(huì)將這個(gè)字符串分割成三部分:controllerNameactionNamequeryString。 例如,URL鏈接為:yoursite.com/item/detail/1/hello,那么route()分割之后,

      • ControllerName名就是:item
      • actionName名就是:detail
      • URL參數(shù)就是:array(1, hello)

      分割完成后,路由方法再實(shí)例化控制器:itemController,并調(diào)用其中的detail方法 。

      4.4 Controller基類

      接下來(lái),就是在 fastphp 中創(chuàng)建MVC基類,包括控制器模型視圖三個(gè)基類。 在fastphp/base/目錄下新建控制器基類,文件名 Controller.php,功能就是總調(diào)度,內(nèi)容如下:

      <?php
      namespace fastphp\base;
      
      /**
       * 控制器基類
       */
      class Controller
      {
          protected $_controller;
          protected $_action;
          protected $_view;
      
          // 構(gòu)造函數(shù),初始化屬性,并實(shí)例化對(duì)應(yīng)模型
          public function __construct($controller, $action)
          {
              $this->_controller = $controller;
              $this->_action = $action;
              $this->_view = new View($controller, $action);
          }
      
          // 分配變量
          public function assign($name, $value)
          {
              $this->_view->assign($name, $value);
          }
      
          // 渲染視圖
          public function render()
          {
              $this->_view->render();
          }
      }

      Controller 類用assign()方法實(shí)現(xiàn)把變量保存到View對(duì)象中。 這樣,在調(diào)用$this->render() 后視圖文件就能顯示這些變量。

      4.5 Model基類

      新建模型基類,繼承自數(shù)據(jù)庫(kù)操作類Sql類。 因?yàn)閿?shù)據(jù)庫(kù)操作比較復(fù)雜,所以SQL操作我們單獨(dú)創(chuàng)建一個(gè)類。 Model基類涉及到3個(gè)類:Model基類本身,它的父類SQL,以及提供數(shù)據(jù)庫(kù)連接句柄的Db類。 在fastphp/base/目錄下新建模型基類文件,名為 Model.php,代碼如下:

      <?php
      namespace fastphp\base;
      
      use fastphp\db\Sql;
      
      class Model extends Sql
      {
          protected $model;
      
          public function __construct()
          {
              // 獲取數(shù)據(jù)庫(kù)表名
              if (!$this->table) {
      
                  // 獲取模型類名稱
                  $this->model = get_class($this);
      
                  // 刪除類名最后的 Model 字符
                  $this->model = substr($this->model, 0, -5);
      
                  // 數(shù)據(jù)庫(kù)表名與類名一致
                  $this->table = strtolower($this->model);
              }
          }
      }

      fastphp/db/目錄下建立一個(gè)數(shù)據(jù)庫(kù)基類 Sql.php,代碼如下:

      <?php
      namespace fastphp\db;
      
      use \PDOStatement;
      
      class Sql
      {
          // 數(shù)據(jù)庫(kù)表名
          protected $table;
      
          // 數(shù)據(jù)庫(kù)主鍵
          protected $primary = &#39;id&#39;;
      
          // WHERE和ORDER拼裝后的條件
          private $filter = &#39;&#39;;
      
          // Pdo bindParam()綁定的參數(shù)集合
          private $param = array();
      
          /**
           * 查詢條件拼接,使用方式:
           *
           * $this->where([&#39;id = 1&#39;,&#39;and title=Web&#39;, ...])->fetch();
           * 為防止注入,建議通過(guò)$param方式傳入?yún)?shù):
           * $this->where([&#39;id = :id&#39;], [&#39;:id&#39; => $id])->fetch();
           *
           * @param array $where 條件
           * @return $this 當(dāng)前對(duì)象
           */
          public function where($where = array(), $param = array())
          {
              if ($where) {
                  $this->filter .= &#39; WHERE &#39;;
                  $this->filter .= implode(&#39; &#39;, $where);
      
                  $this->param = $param;
              }
      
              return $this;
          }
      
          /**
           * 拼裝排序條件,使用方式:
           *
           * $this->order([&#39;id DESC&#39;, &#39;title ASC&#39;, ...])->fetch();
           *
           * @param array $order 排序條件
           * @return $this
           */
          public function order($order = array())
          {
              if($order) {
                  $this->filter .= &#39; ORDER BY &#39;;
                  $this->filter .= implode(&#39;,&#39;, $order);
              }
      
              return $this;
          }
      
          // 查詢所有
          public function fetchAll()
          {
              $sql = sprintf(select * from `%s` %s, $this->table, $this->filter);
              $sth = Db::pdo()->prepare($sql);
              $sth = $this->formatParam($sth, $this->param);
              $sth->execute();
      
              return $sth->fetchAll();
          }
      
          // 查詢一條
          public function fetch()
          {
              $sql = sprintf(select * from `%s` %s, $this->table, $this->filter);
              $sth = Db::pdo()->prepare($sql);
              $sth = $this->formatParam($sth, $this->param);
              $sth->execute();
      
              return $sth->fetch();
          }
      
          // 根據(jù)條件 (id) 刪除
          public function delete($id)
          {
              $sql = sprintf(delete from `%s` where `%s` = :%s, $this->table, $this->primary, $this->primary);
              $sth = Db::pdo()->prepare($sql);
              $sth = $this->formatParam($sth, [$this->primary => $id]);
              $sth->execute();
      
              return $sth->rowCount();
          }
      
          // 新增數(shù)據(jù)
          public function add($data)
          {
              $sql = sprintf(insert into `%s` %s, $this->table, $this->formatInsert($data));
              $sth = Db::pdo()->prepare($sql);
              $sth = $this->formatParam($sth, $data);
              $sth = $this->formatParam($sth, $this->param);
              $sth->execute();
      
              return $sth->rowCount();
          }
      
          // 修改數(shù)據(jù)
          public function update($data)
          {
              $sql = sprintf(update `%s` set %s %s, $this->table, $this->formatUpdate($data), $this->filter);
              $sth = Db::pdo()->prepare($sql);
              $sth = $this->formatParam($sth, $data);
              $sth = $this->formatParam($sth, $this->param);
              $sth->execute();
      
              return $sth->rowCount();
          }
      
          /**
           * 占位符綁定具體的變量值
           * @param PDOStatement $sth 要綁定的PDOStatement對(duì)象
           * @param array $params 參數(shù),有三種類型:
           * 1)如果SQL語(yǔ)句用問(wèn)號(hào)?占位符,那么$params應(yīng)該為
           *    [$a, $b, $c]
           * 2)如果SQL語(yǔ)句用冒號(hào):占位符,那么$params應(yīng)該為
           *    [&#39;a&#39; => $a, &#39;b&#39; => $b, &#39;c&#39; => $c]
           *    或者
           *    [&#39;:a&#39; => $a, &#39;:b&#39; => $b, &#39;:c&#39; => $c]
           *
           * @return PDOStatement
           */
          public function formatParam(PDOStatement $sth, $params = array())
          {
              foreach ($params as $param => &$value) {
                  $param = is_int($param) ? $param + 1 : &#39;:&#39; . ltrim($param, &#39;:&#39;);
                  $sth->bindParam($param, $value);
              }
      
              return $sth;
          }
      
          // 將數(shù)組轉(zhuǎn)換成插入格式的sql語(yǔ)句
          private function formatInsert($data)
          {
              $fields = array();
              $names = array();
              foreach ($data as $key => $value) {
                  $fields[] = sprintf(`%s`, $key);
                  $names[] = sprintf(:%s, $key);
              }
      
              $field = implode(&#39;,&#39;, $fields);
              $name = implode(&#39;,&#39;, $names);
      
              return sprintf((%s) values (%s), $field, $name);
          }
      
          // 將數(shù)組轉(zhuǎn)換成更新格式的sql語(yǔ)句
          private function formatUpdate($data)
          {
              $fields = array();
              foreach ($data as $key => $value) {
                  $fields[] = sprintf(`%s` = :%s, $key, $key);
              }
      
              return implode(&#39;,&#39;, $fields);
          }
      }

      應(yīng)該說(shuō),Sql基類是框架的核心部分。為什么? 因?yàn)橥ㄟ^(guò)它,我們創(chuàng)建了一個(gè) SQL 抽象層,可以大大減少了數(shù)據(jù)庫(kù)的編程工作。 雖然 PDO 接口本來(lái)已經(jīng)很簡(jiǎn)潔,但是抽象之后框架的可靈活性更高。 Sql類里面有用到Db:pdo()方法,這是我們創(chuàng)建的Db類,它提供一個(gè)PDO單例。 在fastphp/db/目錄下創(chuàng)建Db.php文件,內(nèi)容:

      <?php
      namespace fastphp\db;
      
      use PDO;
      use PDOException;
      
      /**
       * 數(shù)據(jù)庫(kù)操作類。
       * 其$pdo屬性為靜態(tài)屬性,所以在頁(yè)面執(zhí)行周期內(nèi),
       * 只要一次賦值,以后的獲取還是首次賦值的內(nèi)容。
       * 這里就是PDO對(duì)象,這樣可以確保運(yùn)行期間只有一個(gè)
       * 數(shù)據(jù)庫(kù)連接對(duì)象,這是一種簡(jiǎn)單的單例模式
       * Class Db
       */
      class Db
      {
          private static $pdo = null;
      
          public static function pdo()
          {
              if (self::$pdo !== null) {
                  return self::$pdo;
              }
      
              try {
                  $dsn    = sprintf(&#39;mysql:host=%s;dbname=%s;charset=utf8&#39;, DB_HOST, DB_NAME);
                  $option = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
      
                  return self::$pdo = new PDO($dsn, DB_USER, DB_PASS, $option);
              } catch (PDOException $e) {
                  exit($e->getMessage());
              }
          }
      }

      4.6 View基類

      fastphp/base/目錄下新建視圖基類 View.php 內(nèi)容如下:

      <?php
      namespace fastphp\base;
      
      /**
       * 視圖基類
       */
      class View
      {
          protected $variables = array();
          protected $_controller;
          protected $_action;
      
          function __construct($controller, $action)
          {
              $this->_controller = strtolower($controller);
              $this->_action = strtolower($action);
          }
      
          // 分配變量
          public function assign($name, $value)
          {
              $this->variables[$name] = $value;
          }
      
          // 渲染顯示
          public function render()
          {
              extract($this->variables);
              $defaultHeader = APP_PATH . &#39;app/views/header.php&#39;;
              $defaultFooter = APP_PATH . &#39;app/views/footer.php&#39;;
      
              $controllerHeader = APP_PATH . &#39;app/views/&#39; . $this->_controller . &#39;/header.php&#39;;
              $controllerFooter = APP_PATH . &#39;app/views/&#39; . $this->_controller . &#39;/footer.php&#39;;
              $controllerLayout = APP_PATH . &#39;app/views/&#39; . $this->_controller . &#39;/&#39; . $this->_action . &#39;.php&#39;;
      
              // 頁(yè)頭文件
              if (is_file($controllerHeader)) {
                  include ($controllerHeader);
              } else {
                  include ($defaultHeader);
              }
      
              //判斷視圖文件是否存在
              if (is_file($controllerLayout)) {
                  include ($controllerLayout);
              } else {
                  echo <h1>無(wú)法找到視圖文件</h1>;
              }
      
              // 頁(yè)腳文件
              if (is_file($controllerFooter)) {
                  include ($controllerFooter);
              } else {
                  include ($defaultFooter);
              }
          }
      }

      這樣,核心的PHP MVC框架核心就完成了。 下面我們編寫應(yīng)用來(lái)測(cè)試框架功能。

      5 應(yīng)用

      5.1 數(shù)據(jù)庫(kù)部署

      在 SQL 中新建一個(gè) project 數(shù)據(jù)庫(kù),增加一個(gè)item 表、并插入兩條記錄,命令如下:

      CREATE DATABASE `project` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
      USE `project`;
      
      CREATE TABLE `item` (
          `id` int(11) NOT NULL auto_increment,
          `item_name` varchar(255) NOT NULL,
          PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
      
      INSERT INTO `item` VALUES(1, &#39;Hello World.&#39;);
      INSERT INTO `item` VALUES(2, &#39;Lets go!&#39;);

      5.2 部署模型

      然后,我們還需要在app/models/目錄中創(chuàng)建一個(gè) ItemModel.php 模型,內(nèi)容如下:

      <?php
      namespace app\models;
      
      use fastphp\base\Model;
      use fastphp\db\Db;
      
      /**
       * 用戶Model
       */
      class ItemModel extends Model
      {
          /**
           * 自定義當(dāng)前模型操作的數(shù)據(jù)庫(kù)表名稱,
           * 如果不指定,默認(rèn)為類名稱的小寫字符串,
           * 這里就是 item 表
           * @var string
           */
          protected $table = &#39;item&#39;;
      
          /**
           * 搜索功能,因?yàn)镾ql父類里面沒(méi)有現(xiàn)成的like搜索,
           * 所以需要自己寫SQL語(yǔ)句,對(duì)數(shù)據(jù)庫(kù)的操作應(yīng)該都放
           * 在Model里面,然后提供給Controller直接調(diào)用
           * @param $title string 查詢的關(guān)鍵詞
           * @return array 返回的數(shù)據(jù)
           */
          public function search($keyword)
          {
              $sql = select * from `$this->table` where `item_name` like :keyword;
              $sth = Db::pdo()->prepare($sql);
              $sth = $this->formatParam($sth, [&#39;:keyword&#39; => %$keyword%]);
              $sth->execute();
      
              return $sth->fetchAll();
          }
      }

      因?yàn)?Item 模型繼承了 Model基類,所以它擁有 Model 類的所有功能。

      5.3 部署控制器

      app/controllers/ 目錄下創(chuàng)建一個(gè) ItemController.php 控制器,內(nèi)容如下:

      <?php
      namespace app\controllers;
      
      use fastphp\base\Controller;
      use app\models\ItemModel;
      
      class ItemController extends Controller
      {
          // 首頁(yè)方法,測(cè)試框架自定義DB查詢
          public function index()
          {
              $keyword = isset($_GET[&#39;keyword&#39;]) ? $_GET[&#39;keyword&#39;] : &#39;&#39;;
      
              if ($keyword) {
                  $items = (new ItemModel())->search($keyword);
              } else {
                  // 查詢所有內(nèi)容,并按倒序排列輸出
                  // where()方法可不傳入?yún)?shù),或者省略
                  $items = (new ItemModel)->where()->order([&#39;id DESC&#39;])->fetchAll();
              }
      
              $this->assign(&#39;title&#39;, &#39;全部條目&#39;);
              $this->assign(&#39;keyword&#39;, $keyword);
              $this->assign(&#39;items&#39;, $items);
              $this->render();
          }
      
          // 查看單條記錄詳情
          public function detail($id)
          {
              // 通過(guò)?占位符傳入$id參數(shù)
              $item = (new ItemModel())->where([id = ?], [$id])->fetch();
      
              $this->assign(&#39;title&#39;, &#39;條目詳情&#39;);
              $this->assign(&#39;item&#39;, $item);
              $this->render();
          }
      
          // 添加記錄,測(cè)試框架DB記錄創(chuàng)建(Create)
          public function add()
          {
              $data[&#39;item_name&#39;] = $_POST[&#39;value&#39;];
              $count = (new ItemModel)->add($data);
      
              $this->assign(&#39;title&#39;, &#39;添加成功&#39;);
              $this->assign(&#39;count&#39;, $count);
              $this->render();
          }
      
          // 操作管理
          public function manage($id = 0)
          {
              $item = array();
              if ($id) {
                  // 通過(guò)名稱占位符傳入?yún)?shù)
                  $item = (new ItemModel())->where([id = :id], [&#39;:id&#39; => $id])->fetch();
              }
      
              $this->assign(&#39;title&#39;, &#39;管理?xiàng)l目&#39;);
              $this->assign(&#39;item&#39;, $item);
              $this->render();
          }
      
          // 更新記錄,測(cè)試框架DB記錄更新(Update)
          public function update()
          {
              $data = array(&#39;id&#39; => $_POST[&#39;id&#39;], &#39;item_name&#39; => $_POST[&#39;value&#39;]);
              $count = (new ItemModel)->where([&#39;id = :id&#39;], [&#39;:id&#39; => $data[&#39;id&#39;]])->update($data);
      
              $this->assign(&#39;title&#39;, &#39;修改成功&#39;);
              $this->assign(&#39;count&#39;, $count);
              $this->render();
          }
      
          // 刪除記錄,測(cè)試框架DB記錄刪除(Delete)
          public function delete($id = null)
          {
              $count = (new ItemModel)->delete($id);
      
              $this->assign(&#39;title&#39;, &#39;刪除成功&#39;);
              $this->assign(&#39;count&#39;, $count);
              $this->render();
          }
      }

      5.4 部署視圖

      app/views/目錄下新建 header.php 和 footer.php 兩個(gè)頁(yè)頭頁(yè)腳模板,如下。 header.php 內(nèi)容:

      <html>
      <head>
          <meta http-equiv=Content-Type content=text/html; charset=utf-8 />
          <title><?php echo $title ?></title>
          <link rel=stylesheet href=/static/css/main.css type=text/css />
      </head>
      <body>
          <h1><?php echo $title ?></h1>

      footer.php 內(nèi)容:

      </body>
      </html>

      頁(yè)頭文件用到了main.css樣式文件,內(nèi)容:

      html, body {
      margin: 0;
      padding: 10px;
      font-size: 20px;
      }
      
      input {
      font-family:georgia,times;
      font-size:24px;
      line-height:1.2em;
      }
      
      a {
      color:blue;
      font-family:georgia,times;
      line-height:1.2em;
      text-decoration:none;
      }
      
      a:hover {
      text-decoration:underline;
      }
      
      h1 {
      color:#000000;
      font-size:41px;
      border-bottom:1px dotted #cccccc;
      }
      
      td {padding: 1px 30px 1px 0;}

      然后,在 app/views/item 目錄下創(chuàng)建以下幾個(gè)視圖文件。 index.php,瀏覽數(shù)據(jù)庫(kù)內(nèi) item 表的所有記錄,內(nèi)容:

      <form action= method=get>
          <input type=text value=<?php echo $keyword ?> name=keyword>
          <input type=submit value=搜索>
      </form>
      
      <p><a href=/item/manage>新建</a></p>
      
      <table>
          <tr>
              <th>ID</th>
              <th>內(nèi)容</th>
              <th>操作</th>
          </tr>
          <?php foreach ($items as $item): ?>
              <tr>
                  <td><?php echo $item[&#39;id&#39;] ?></td>
                  <td><?php echo $item[&#39;item_name&#39;] ?></td>
                  <td>
                      <a href=/item/manage/<?php echo $item[&#39;id&#39;] ?>>編輯</a>
                      <a href=/item/delete/<?php echo $item[&#39;id&#39;] ?>>刪除</a>
                  </td>
              </tr>
          <?php endforeach ?>
      </table>

      add.php,添加記錄后的提示,內(nèi)容:

      <a class=big href=/item/index>成功添加<?php echo $count ?>條記錄,點(diǎn)擊返回</a>

      manage.php,管理記錄,內(nèi)容:

      <form action=<?php echo $postUrl; ?> method=post>
          <?php if (isset($item[&#39;id&#39;])): ?>
              <input type=hidden name=id value=<?php echo $item[&#39;id&#39;] ?>>
          <?php endif; ?>
          <input type=text name=value value=<?php echo isset($item[&#39;item_name&#39;]) ? $item[&#39;item_name&#39;] : &#39;&#39; ?>>
          <input type=submit value=提交>
      </form>
      
      <a class=big href=/item/index>返回</a>

      update.php,更改記錄后的提示,內(nèi)容:

      <a class=big href=/item/index>成功修改<?php echo $count ?>項(xiàng),點(diǎn)擊返回</a>

      delete.php,刪除記錄后的提示,內(nèi)容:

      <a href=/item/index>成功刪除<?php echo $count ?>項(xiàng),點(diǎn)擊返回</a>

      6 應(yīng)用測(cè)試

      這樣,在瀏覽器中訪問(wèn) project程序:http://localhost/item/index/,就可以看到效果了。
      編寫PHP MVC框架【保姆級(jí)教程推薦】

      以上代碼已經(jīng)全部發(fā)布到 github 上,關(guān)鍵部分加了注釋:

      • 倉(cāng)庫(kù)地址:https://github.com/yeszao/fastphp
      • 源碼打包:https://github.com/yeszao/fastphp/archive/master.zip

      以上是編寫PHP MVC框架【保姆級(jí)教程推薦】的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

      本站聲明
      本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

      熱AI工具

      Undress AI Tool

      Undress AI Tool

      免費(fèi)脫衣服圖片

      Undresser.AI Undress

      Undresser.AI Undress

      人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

      AI Clothes Remover

      AI Clothes Remover

      用于從照片中去除衣服的在線人工智能工具。

      Clothoff.io

      Clothoff.io

      AI脫衣機(jī)

      Video Face Swap

      Video Face Swap

      使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

      熱工具

      記事本++7.3.1

      記事本++7.3.1

      好用且免費(fèi)的代碼編輯器

      SublimeText3漢化版

      SublimeText3漢化版

      中文版,非常好用

      禪工作室 13.0.1

      禪工作室 13.0.1

      功能強(qiáng)大的PHP集成開發(fā)環(huán)境

      Dreamweaver CS6

      Dreamweaver CS6

      視覺(jué)化網(wǎng)頁(yè)開發(fā)工具

      SublimeText3 Mac版

      SublimeText3 Mac版

      神級(jí)代碼編輯軟件(SublimeText3)

      熱門話題

      Laravel 教程
      1601
      29
      PHP教程
      1502
      276
      PHP變量范圍解釋了 PHP變量范圍解釋了 Jul 17, 2025 am 04:16 AM

      PHP變量作用域常見(jiàn)問(wèn)題及解決方法包括:1.函數(shù)內(nèi)部無(wú)法訪問(wèn)全局變量,需使用global關(guān)鍵字或參數(shù)傳入;2.靜態(tài)變量用static聲明,只初始化一次并在多次調(diào)用間保持值;3.超全局變量如$_GET、$_POST可在任何作用域直接使用,但需注意安全過(guò)濾;4.匿名函數(shù)需通過(guò)use關(guān)鍵字引入父作用域變量,修改外部變量則需傳遞引用。掌握這些規(guī)則有助于避免錯(cuò)誤并提升代碼穩(wěn)定性。

      如何在PHP中牢固地處理文件上傳? 如何在PHP中牢固地處理文件上傳? Jul 08, 2025 am 02:37 AM

      要安全處理PHP文件上傳需驗(yàn)證來(lái)源與類型、控制文件名與路徑、設(shè)置服務(wù)器限制并二次處理媒體文件。1.驗(yàn)證上傳來(lái)源通過(guò)token防止CSRF并通過(guò)finfo_file檢測(cè)真實(shí)MIME類型使用白名單控制;2.重命名文件為隨機(jī)字符串并根據(jù)檢測(cè)類型決定擴(kuò)展名存儲(chǔ)至非Web目錄;3.PHP配置限制上傳大小及臨時(shí)目錄Nginx/Apache禁止訪問(wèn)上傳目錄;4.GD庫(kù)重新保存圖片清除潛在惡意數(shù)據(jù)。

      在PHP中評(píng)論代碼 在PHP中評(píng)論代碼 Jul 18, 2025 am 04:57 AM

      PHP注釋代碼常用方法有三種:1.單行注釋用//或#屏蔽一行代碼,推薦使用//;2.多行注釋用/.../包裹代碼塊,不可嵌套但可跨行;3.組合技巧注釋如用/if(){}/控制邏輯塊,或配合編輯器快捷鍵提升效率,使用時(shí)需注意閉合符號(hào)和避免嵌套。

      發(fā)電機(jī)如何在PHP中工作? 發(fā)電機(jī)如何在PHP中工作? Jul 11, 2025 am 03:12 AM

      AgeneratorinPHPisamemory-efficientwaytoiterateoverlargedatasetsbyyieldingvaluesoneatatimeinsteadofreturningthemallatonce.1.Generatorsusetheyieldkeywordtoproducevaluesondemand,reducingmemoryusage.2.Theyareusefulforhandlingbigloops,readinglargefiles,or

      撰寫PHP評(píng)論的提示 撰寫PHP評(píng)論的提示 Jul 18, 2025 am 04:51 AM

      寫好PHP注釋的關(guān)鍵在于明確目的與規(guī)范,注釋應(yīng)解釋“為什么”而非“做了什么”,避免冗余或過(guò)于簡(jiǎn)單。1.使用統(tǒng)一格式,如docblock(/*/)用于類、方法說(shuō)明,提升可讀性與工具兼容性;2.強(qiáng)調(diào)邏輯背后的原因,如說(shuō)明為何需手動(dòng)輸出JS跳轉(zhuǎn);3.在復(fù)雜代碼前添加總覽性說(shuō)明,分步驟描述流程,幫助理解整體思路;4.合理使用TODO和FIXME標(biāo)記待辦事項(xiàng)與問(wèn)題,便于后續(xù)追蹤與協(xié)作。好的注釋能降低溝通成本,提升代碼維護(hù)效率。

      學(xué)習(xí)PHP:初學(xué)者指南 學(xué)習(xí)PHP:初學(xué)者指南 Jul 18, 2025 am 04:54 AM

      易于效率,啟動(dòng)啟動(dòng)tingupalocalserverenverenvirestoolslikexamppandacodeeditorlikevscode.1)installxamppforapache,mysql,andphp.2)uscodeeditorforsyntaxssupport.3)

      如何通過(guò)php中的索引訪問(wèn)字符串中的字符 如何通過(guò)php中的索引訪問(wèn)字符串中的字符 Jul 12, 2025 am 03:15 AM

      在PHP中獲取字符串特定索引字符可用方括號(hào)或花括號(hào),但推薦方括號(hào);索引從0開始,超出范圍訪問(wèn)返回空值,不可賦值;處理多字節(jié)字符需用mb_substr。例如:$str="hello";echo$str[0];輸出h;而中文等字符需用mb_substr($str,1,1)獲取正確結(jié)果;實(shí)際應(yīng)用中循環(huán)訪問(wèn)前應(yīng)檢查字符串長(zhǎng)度,動(dòng)態(tài)字符串需驗(yàn)證有效性,多語(yǔ)言項(xiàng)目建議統(tǒng)一使用多字節(jié)安全函數(shù)。

      快速PHP安裝教程 快速PHP安裝教程 Jul 18, 2025 am 04:52 AM

      ToinstallPHPquickly,useXAMPPonWindowsorHomebrewonmacOS.1.OnWindows,downloadandinstallXAMPP,selectcomponents,startApache,andplacefilesinhtdocs.2.Alternatively,manuallyinstallPHPfromphp.netandsetupaserverlikeApache.3.OnmacOS,installHomebrew,thenrun'bre

      See all articles

    • <center id="pdll3"></center>