日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

MVC是一個老生常談的問題,是為了解決一類共同問題總結出來的一套可復用的解決方案,這是軟件設計模式產(chǎn)生的初衷。不管是客戶端還是移動端,MVC的分層設計模式解決了軟件開發(fā)中的可復用、單一職責、解耦的問題,php語言中的MVC設置模式也是如此。下面通過PHP語言細說MVC模式如何在PHP中應用,本文主要從如下幾方面介紹:

Ø MVC的工作原理

Ø PHP開發(fā)框架

a) 開發(fā)框架的優(yōu)勢

b) 使用框架進行模塊劃分

Ø 一個簡單MVC框架總體架構分析

a) URL訪問方式【URL Parser】

b) 控制器【Controller】

c) 視圖【View】

d) 運行時【Runtime】

1、MVC 的工作原理

MVC框架圖:

視圖View

代表用戶交互的頁面、可以包含html界面、Smarty模板等和界面相關的元素。MVC設計模式對于視圖的處理僅限于視圖上數(shù)據(jù)的采集和處理,以及用戶的點擊、拖動等事件的處理,而不包括在視圖上的業(yè)務流程處理。業(yè)務流程會交給模型層(Model)處理。

模型Model

模型層是對業(yè)務流程、狀態(tài)的處理以及業(yè)務規(guī)則的指定。業(yè)務流程的處理過程對其他層來說是黑箱操作,模型接受視圖的請求處理數(shù)據(jù),返回最終的處理結果。業(yè)務模型還有一個很重要的模型--數(shù)據(jù)模型,數(shù)據(jù)模型主要指實體對象的數(shù)據(jù)保存(持久化)。比如將一張訂單保存到數(shù)據(jù)庫,從數(shù)據(jù)庫獲取訂單,所有和數(shù)據(jù)庫相關的操作限定在該模型中。

控制器Controller

控制層是View層和Model層之間的一個橋梁,接收到用戶的請求,將模型和視圖匹配在一起,共同完成用戶的請求。比如,用戶點擊一個鏈接,控制層接收到請求后,把信息傳遞給模型層,模型層處理完成之后返回視圖給用戶。

2、PHP開發(fā)框架

2.1、開發(fā)框架的優(yōu)勢

  • 框架提高開發(fā)效率和質(zhì)量
  • 框架處理了許多基礎性工作
  • 框架處理細節(jié)工作(事務處理、安全、數(shù)據(jù)流控制)
  • 框架結構性好、擴張性好
  • 框架劃分子問題,易于控制、易于延展、易于分配資源

2.2、使用框架進行模塊劃分

一個典型的后臺應用模塊的劃分

  • 平臺操作管理
    • 登錄管理
    • 操作界面管理
  • 系統(tǒng)管理頻道
    • 常規(guī)管理
    • 公告管理
    • 友情鏈接掛你
  • 內(nèi)容管理頻道
    • 圖片管理
    • 欄目管理
    • 文章管理
    • 幻燈片管理
  • 用戶管理頻道
    • 用戶組管理
    • 用戶管理

模塊設置操作

  • 每個模塊可以設置查看、添加、修改、刪除、搜索等操作
  • 模塊太大應該劃分子模塊,適合的模塊數(shù)量為8~12個


3、一個簡單MVC框架的分析

從以下五個方面來分析

  1. URL訪問方式(URL Parser)
  2. 控制器(Controller)
  3. 視圖(View)
  4. 模型(Model)
  5. 運行時(Runtime)

3.1、URL訪問方式(URL Parser)

URL使用PATHINFO模式(index.php/index/index/),應用的訪問方式都是采用單一入口的訪問方式,所有訪問一個應用中的具體模塊及模塊中的某個操作,都需要在URL中通過入口文件后的參數(shù)來訪問和執(zhí)行,所有訪問都會變成由URL的參數(shù)來統(tǒng)一解析和調(diào)度,格式如下:

不帶參數(shù)的URL
http://example.com/index.php/user/add
帶有參數(shù)的URL
http://example.com/index.php/user/add/cid/5
http://example.com/index.php/user/add/cid/5/page/6

這種采用單一入口和PATHINFO模式的URL訪問是MVC實現(xiàn)的基礎,作為單一入口的框架的入口brophp.php文件則負責處理基本的信息,包括了

  • 路徑信息:BroPHP框架的路徑,用戶項目的應用路徑,項目的根路徑等
  • 包含框架中的函數(shù)庫文件
  • 包含全局的函數(shù)庫文件,用戶可以自己定義函數(shù)在這個文件中
  • __autoload()自動加載類
  • 頁面緩存配置
  • 初使化時,創(chuàng)建項目的目錄結構
  • 解析處理URL

1)路徑信息處理

路徑信息會保存在$GLOBALS全局數(shù)組中,后面的頁面需要使用到直接從$GLOBALS中獲取即可

//模板文件中所有要的路徑,htmlcssJAVAscriptimagelink等中用到的路徑,從WEB服務器的文檔根開始
$spath = dirname($_SERVER["SCRIPT_NAME"]);
if ($spath == "/" || $spath == "\")
$spath = "";
$GLOBALS["root"] = $spath . '/'; //Web服務器根到項目的根
$GLOBALS["App"] = $_SERVER["SCRIPT_NAME"] . '/'; //當前應用腳本文件
$GLOBALS["url"] = $GLOBALS["app"] . $_GET["m"] . '/'; //訪問到當前模塊
$GLOBALS["public"] = $GLOBALS["root"] . 'public/'; //項目的全局資源目錄
$GLOBALS["res"] = $GLOBALS["root"] . ltrim(APP_PATH, './') . "views/" . TPLSTYLE . "/resource/"; //當前應用模板的資源

2)包含框架中的函數(shù)庫文件

函數(shù)庫文件主要是一些常用的工具方法的集合,框架自帶的functions.inc.php方法庫包含了數(shù)據(jù)模型創(chuàng)建操作的一些列工具方法,可以開箱即用。此外用戶也可以自定義函數(shù)庫文件保存在對應模塊目錄下的commons/functions.inc.php位置,框架會自動引入。

 //包含框架中的函數(shù)庫文件

 include BROPHP_PATH . 'commons/functions.inc.php';

 ?

 // 包含全局的函數(shù)庫文件,用戶可以自己定義函數(shù)在這個文件中

 $funfile = PROJECT_PATH . "commons/functions.inc.php";

 if (file_exists($funfile))

 include $funfile;

3)設置包含目錄(類所在的全部目錄)

這個步驟是__autoload()自動加載類的基礎,__autoload()方法中include會自動從這些目錄中尋找要包含的類

 //設置包含目錄(類所在的全部目錄), PATH_SEPARATOR 分隔符號 linux(:) windows(;)

 $include_path = get_include_path(); //原基目錄

 $include_path .= PATH_SEPARATOR . BROPHP_PATH . "bases/"; //框架中基類所在的目錄

 $include_path .= PATH_SEPARATOR . BROPHP_PATH . "classes/"; //框架中擴展類的目錄

 $include_path .= PATH_SEPARATOR . BROPHP_PATH . "libs/"; //模板Smarty所在的目錄

 $include_path .= PATH_SEPARATOR . PROJECT_PATH . "classes/"; //項目中用的到的工具類

 $controlerpath = PROJECT_PATH . "runtime/controls/" . TMPPATH; //生成控制器所在的路徑

 $include_path .= PATH_SEPARATOR . $controlerpath; //當前應用的控制類所在的目錄


 //設置include包含文件所在的所有目錄

 set_include_path($include_path);

4)__autoload()自動加載類

__autoload()魔術方法是在用戶創(chuàng)建一個沒有包含的類的對象之前會調(diào)用,所以重寫這個方法,在這個方法中處理類文件的包含,省去了類文件包含的工作,當然類名需要符合一定的規(guī)則才能使用自動包含,框架定義了類名的規(guī)則為“首字母大小的類名.clsss.php”

 //自動加載類

 function __autoload($className)

 {

 if ($className == "memcache") { //如果是系統(tǒng)的Memcache類則不包含

 return;

 } else if ($className == "Smarty") { //如果類名是Smarty類,則直接包含

 include "Smarty.class.php";

 } else { //如果是其他類,將類名轉(zhuǎn)為小寫

 include strtolower($className) . ".class.php";

 }

 Debug::addmsg("<b> $className </b>類", 1); //在debug中顯示自動包含的類

 }

解析處理URL

解析處理URL步驟調(diào)用的是Prourl::parseUrl();

 /**

 * URL路由,轉(zhuǎn)為PATHINFO的格式

 */

 static function parseUrl()

 {

 if (isset($_SERVER['PATH_INFO'])) {

 //獲取 pathinfo

 $pathinfo = explode('/', trim($_SERVER['PATH_INFO'], "/"));

 ?

 // 獲取 control

 $_GET['m'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index');

 ?

 array_shift($pathinfo); //將數(shù)組開頭的單元移出數(shù)組 

 ?

 // 獲取 action

 $_GET['a'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index');

 array_shift($pathinfo); //再將將數(shù)組開頭的單元移出數(shù)組 

 ?

 for ($i = 0; $i < count($pathinfo); $i += 2) {

 $_GET[$pathinfo[$i]] = $pathinfo[$i + 1];

 }

 ?

 } else {

 $_GET["m"] = (!empty($_GET['m']) ? $_GET['m'] : 'index'); //默認是index模塊

 $_GET["a"] = (!empty($_GET['a']) ? $_GET['a'] : 'index'); //默認是index動作

 ?

 if ($_SERVER["QUERY_STRING"]) {

 $m = $_GET["m"];

 unset($_GET["m"]); //去除數(shù)組中的m

 $a = $_GET["a"];

 unset($_GET["a"]); //去除數(shù)組中的a

 $query = http_build_query($_GET); //形成0=foo&1=bar&2=baz&3=boom&cow=milk格式

 //組成新的URL

 $url = $_SERVER["SCRIPT_NAME"] . "/{$m}/{$a}/" . str_replace(array("&", "="), "/", $query);

 header("Location:" . $url);

 }

 }

 }

訪問login/index,解析保存在全局的GET數(shù)組中的信息如下:

m -> control 表示控制器
a -> action 表示操作

有了這些信息,動態(tài)創(chuàng)建控制器,發(fā)起對應的流程

 $className = ucfirst($_GET["m"]) . "Action";

 $controler = new $className();

 $controler->run();

3.2、控制器(Controller)

1)控制器的聲明

功能模塊的控制器類保存在controls目錄中,類名和模塊名相同,下面是登錄模塊,定義一個Login類(類的首字母需要大寫)保存的文件名為login.class.php

 class Login extends Action

 {

 function __construct()

 {

 parent::__construct();

 }

 ?

 function index()

 {//登陸頁面

 $GLOBALS['debug'] = 0;

 $this->display();

 }

 function islogin()

 {

 if ($_POST['user_username'] == null && $_POST['user_password'] == null) {//如果用戶名為空

 $this->error('用戶名和密碼不能為空', 1, '');

 }

 $_POST['user_password'] = md5($_POST['user_password']);

 $_POST['user_repassword'] = md5($_POST['user_repassword']);

 if ($_POST['user_repassword'] != $_POST['user_password']) {//如果用戶輸入的兩次密碼不一致

 $this->error('兩次密碼不一致', 1, '');

 }

 $user = D('user');

 $date = $user->field('uid,user_password')->where(array('user_username' => $_POST['user_username']))->find();

 $_POST['uid'] = $date['uid'];

 if ($_POST['user_password'] != $date['user_password']) {//如果輸入的密碼與數(shù)據(jù)庫密碼不匹配

 $this->error('密碼不正確', 1, '');

 }

 if (strtoupper($_POST['code']) != $_SESSION['code']) {//如果輸入的驗證碼不正確

 $this->error('驗證碼輸入不正確', 1, '');

 }

 $_SESSION = $_POST;//把posts所有的數(shù)據(jù)壓入session

 $date = $user->query('SELECT free_user_group.group_muser,free_user_group.group_mweb,free_user_group.group_marticle,free_user_group.group_sendarticle,free_user_group.group_mimage,free_user_group.group_sendcomment,free_user_group.group_sendmessage,free_user.user_lock FROM free_user,free_user_group WHERE free_user.uid=' . $_SESSION['uid'] . ' AND free_user.gid=free_user_group.gid', 'select');

 if ($date[0]['user_lock']) {

 $this->error('您的帳號已被鎖定,請與管理員聯(lián)系后再登錄', 3, 'index/index');

 } else {

 if ($date[0]['group_muser'] || $date[0]['group_marticle'] || $date[0]['group_mweb'] || $date[0]['group_mimage']) {

 //查詢數(shù)據(jù)庫中是否開啟自動記錄操作

 $opernote = D('foreground');

 //$_SESSION['oper']=D('OperDate');

 $isOpenNote = $opernote->where(array('fid' => '1'))->field('operateNotes')->find();

 //$_SESSION['operAuthor']=$operAuthior->where(array('id'=>'1'))->find();

 $_SESSION['isOpenNotes'] = $isOpenNote['operateNotes'];

 $_SESSION['islogin'] = true;

 $_SESSION = array_merge($date[0], $_SESSION);

 $user->where($_SESSION['uid'])->update('user_onlinestatus=user_onlinestatus+1');

 $this->success('登陸成功', 1, 'index/index');

 } else {

 $this->error('您的權限不夠無法進入后臺', 1, '');

 }

 }

 }

 function logout()

 {//退出時銷毀session

 $user = D('user');

 $_SESSION['islogin'] = false;

 $_SESSION = array();

 if (isset($_COOKIE[session_name()])) {

 setCookie(session_name(), '', time() - 3600, '/');

 }

 session_destroy();

 $this->redirect('index');

 }

 ?

 function code()

 {//顯示驗證碼

 echo new Vcode();

 }

 }

common.class.php 類

 class Common extends Action

 {

 function init()

 {

 if (!(isset($_SESSION['islogin']) && $_SESSION['islogin'] == true)) {

 $this->redirect("login/index");

 }

 $this->assign('session', $_SESSION);

 }

 }

2) 操作的聲明

每個操作對應的是控制器中的一個方法,比如在上面的Login控制器中

  • code()是一個獲取驗證碼的操作,可以通過 yourhost:port/.../Login/code 這種方式訪問該操作
  • logout()是一個退出登錄的操作,可以通過yourhost:port/.../Login/logout這種方式訪問該操作

3.3、視圖(View)

視圖的顯示是基于Smarty模板引擎的,繼承了Smarty類,并且重寫了__construct,display,is_cached,clear_cache 方法。

<?php
class Mytpl extends Smarty
{
/**
* 構造方法,用于初使化Smarty對象中的成員屬性
*
*/
function __construct()
{
$this->template_dir = APP_PATH . "views/" . TPLSTYLE; //模板目錄
$this->compile_dir = PROJECT_PATH . "runtime/comps/" . TPLSTYLE . "/" . TMPPATH; //里的文件是自動生成的,合成的文件
$this->caching = CSTART; //設置緩存開啟
$this->cache_dir = PROJECT_PATH . "runtime/cache/" . TPLSTYLE; //設置緩存的目錄
$this->cache_lifetime = CTIME; //設置緩存的時間
$this->left_delimiter = "<{"; //模板文件中使用的“左”分隔符號
$this->right_delimiter = "}>"; //模板文件中使用的“右”分隔符號
parent::__construct(); //調(diào)用父類被覆蓋的構造方法
}
?
/*
* 重載父類Smarty類中的方法
* @param string $resource_name 模板的位置
* @param mixed $cache_id 緩存的ID
*/
function display($resource_name = null, $cache_id = null, $compile_id = null)
{
?
//將部分全局變量直接分配到模板中使用
$this->assign("root", rtrim($GLOBALS["root"], "/"));
$this->assign("app", rtrim($GLOBALS["app"], "/"));
$this->assign("url", rtrim($GLOBALS["url"], "/"));
$this->assign("public", rtrim($GLOBALS["public"], "/"));
$this->assign("res", rtrim($GLOBALS["res"], "/"));
?
if (is_null($resource_name)) {
$resource_name = "{$_GET["m"]}/{$_GET["a"]}." . TPLPREFIX;
} else if (strstr($resource_name, "/")) {
$resource_name = $resource_name . "." . TPLPREFIX;
} else {
$resource_name = $_GET["m"] . "/" . $resource_name . "." . TPLPREFIX;
}
Debug::addmsg("使用模板 <b> $resource_name </b>");
parent::display($resource_name, $cache_id, $compile_id);
}
?
/*
* 重載父類的Smarty類中的方法
* @param string $tpl_file 模板文件
* @param mixed $cache_id 緩存的ID
*/
function is_cached($tpl_file = null, $cache_id = null, $compile_id = null)
{
if (is_null($tpl_file)) {
$tpl_file = "{$_GET["m"]}/{$_GET["a"]}." . TPLPREFIX;
} else if (strstr($tpl_file, "/")) {
$tpl_file = $tpl_file . "." . TPLPREFIX;
} else {
$tpl_file = $_GET["m"] . "/" . $tpl_file . "." . TPLPREFIX;
}
return parent::is_cached($tpl_file, $cache_id, $compile_id);
}
?
/*
* 重載父類的Smarty類中的方法
* @param string $tpl_file 模板文件
* @param mixed $cache_id 緩存的ID
*/
?
function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null)
{
if (is_null($tpl_file)) {
$tpl_file = "{$_GET["m"]}/{$_GET["a"]}." . TPLPREFIX;
} else if (strstr($tpl_file, "/")) {
$tpl_file = $tpl_file . "." . TPLPREFIX;
} else {
$tpl_file = $_GET["m"] . "/" . $tpl_file . "." . TPLPREFIX;
}
return parent::clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null);
}
}

比如訪問登錄頁面

 function index()

 {//登陸頁面

 $GLOBALS['debug'] = 0;

 $this->display();

 }

類Mytpl的構造方法會自動初始化Smarty的模板目錄、編譯目錄、緩存目錄等Smarty模板引擎需要的內(nèi)容

 $this->template_dir = APP_PATH . "views/" . TPLSTYLE; //模板目錄

 $this->compile_dir = PROJECT_PATH . "runtime/comps/" . TPLSTYLE . "/" . TMPPATH; //里的文件是自動生成的,合成的文件

 $this->caching = CSTART; //設置緩存開啟

 $this->cache_dir = PROJECT_PATH . "runtime/cache/" . TPLSTYLE; //設置緩存的目錄

主要內(nèi)容如下:

 template_dir = "./admin/views/default"

 compile_dir = "./runtime/comps/default/admin_php/"

 cache_dir = "./runtime/cache/default"

 cache_lifetime = 604800

在Login控制器中調(diào)用無參的$this->display();方法,會自動從$this->template_dir文件夾下面查找模板文件,模板文件的是保存在_GET["m"]子文件夾下的名稱為_GET["a"]的文件,比如,Login控制器對應的index模板位于如下位置:

最后使用Smarty模板引擎完成頁面內(nèi)容的渲染工作,最終把編譯后的模板文件保存在$this->compile_dir目錄下面,如下所示:

3.4、模型(Model)

模型層分為業(yè)務模型和數(shù)據(jù)模型,業(yè)務模型用于處理業(yè)務流程中的數(shù)據(jù)驗證、數(shù)據(jù)處理、結果輸出等等步驟;數(shù)據(jù)模型處理數(shù)據(jù)的持久化(增刪改查等操作),數(shù)據(jù)模型承擔了重要的責任,所以會圍繞數(shù)據(jù)模型的底層處理展開來說。

  • insert
  • delete
  • update

模型層的基類是抽象的DB類,有以下幾個重要的公有屬性

 protected $tabName = ""; //表名,自動獲取

 protected $fieldList = array(); //表字段結構,自動獲取

 protected $auto;

 //SQL的初使化

 protected $sql = array("field" => "", "where" => "", "order" => "", "limit" => "", "group" => "", "having" => "");

$sql變量保存了以下信息

  • field 表字段
  • where where字句
  • order order by 字句
  • limit limit 字句
  • group group 字句
  • having having 字句

調(diào)用field() where() order() limit() group() having()方法,會把對應的參數(shù)值保存在$sql關聯(lián)數(shù)key對應的value中,這些方法在實際中不存在,而是通過重寫__call方法實現(xiàn)了

 /**

 *連貫操作調(diào)用field() where() order() limit() group() having()方法,組合SQL語句

 */

 function __call($methodName, $args)

 {

 $methodName = strtolower($methodName);

 if (array_key_exists($methodName, $this->sql)) {

 if (empty($args[0]) || (is_string($args[0]) && trim($args[0]) === '')) {

 $this->sql[$methodName] = "";

 } else {

 $this->sql[$methodName] = $args;

 }

 ?

 if ($methodName == "limit") {

 if ($args[0] == "0")

 $this->sql[$methodName] = $args;

 }

 } else {

 Debug::addmsg("<font color='red'>調(diào)用類" . get_class($this) . "中的方法{$methodName}()不存在!</font>");

 }

 return $this;

 }

比如執(zhí)行下面的代碼:

 $date=$user->field('uid,user_password')->where(array('user_username'=>$_POST['user_username']))->find();

最終$sql中保存的數(shù)據(jù)如下:

 arra (

 "field" => 'uid,user_password',

 "where" => array('user_username'=>"xxxxx")

 )

表名稱和表字段結構
protected $fieldList = array(); 和 $tabName,在dpdp類setTable方法中自動獲取

 /**

 * 自動獲取表結構

 */

 function setTable($tabName)

 {

 $cachefile = PROJECT_PATH . "runtime/data/" . $tabName . ".php";

 $this->tabName = TABPREFIX . $tabName; //加前綴的表名

 ?

 if (!file_exists($cachefile)) {

 try {

 $pdo = self::connect();

 $stmt = $pdo->prepare("desc {$this->tabName}");

 $stmt->execute();

 $auto = "yno";

 $fields = array();

 while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {

 if ($row["Key"] == "PRI") {

 $fields["pri"] = strtolower($row["Field"]);

 } else {

 $fields[] = strtolower($row["Field"]);

 }

 if ($row["Extra"] == "auto_increment")

 $auto = "yes";

 }

 //如果表中沒有主鍵,則將第一列當作主鍵

 if (!array_key_exists("pri", $fields)) {

 $fields["pri"] = array_shift($fields);

 }

 if (!DEBUG)

 file_put_contents($cachefile, "<?php " . json_encode($fields) . $auto);

 $this->fieldList = $fields;

 $this->auto = $auto;

 } catch (PDOException $e) {

 Debug::addmsg("<font color='red'>異常:" . $e->getMessage() . '</font>');

 }

 } else {

 $json = ltrim(file_get_contents($cachefile), "<?ph ");

 $this->auto = substr($json, -3);

 $json = substr($json, 0, -3);

 $this->fieldList = (array)json_decode($json, true);

 }

 Debug::addmsg("表<b>{$this->tabName}</b>結構:" . implode(",", $this->fieldList), 2); //debug

 }

3.5、運行時(Runtime)

· 處理模塊類的隱式集成common類,處理統(tǒng)一的業(yè)務,比如用戶驗證

· 處理運行時生成對應數(shù)據(jù)庫驅(qū)動的數(shù)據(jù)模型

1)運行時數(shù)據(jù)模型

以一個簡單的數(shù)據(jù)庫表查詢作為例子,

 function test_query() {

 $article = D("article");

 $data = $article->query("SELECT * FROM article", "select");

 print_r($data);

 }

整體步驟流程:

 整體步驟流程:

 D("article") -> Structure::model($className, $app);

 -> $model->setTable($className);

 $article->query("SELECT * FROM article", "select");

1、 D("article")中D方法的職責如下:

· 運行時生成數(shù)據(jù)模型

· 獲取數(shù)據(jù)模型對應的數(shù)據(jù)庫表的字段以及其他表信息

 /**

 * 創(chuàng)建Models中的數(shù)據(jù)庫操作對象

 * @param string $className 類名或表名

 * @param string $app 應用名,訪問其他應用的Model

 * @return object 數(shù)據(jù)庫連接對象

 */

 function D($className = null, $app = "")

 {

 $db = null;

 //如果沒有傳表名或類名,則直接創(chuàng)建DB對象,但不能對表進行操作

 if (is_null($className)) {

 $class = "D" . DRIVER;

 $db = new $class;

 } else {

 $className = strtolower($className);

 $model = Structure::model($className, $app);

 $model = new $model();

 //如果表結構不存在,則獲取表結構

 $model->setTable($className);

 $db = $model;

 }

 if ($app == "")

 $db->path = APP_PATH;

 else

 $db->path = PROJECT_PATH . strtolower($app) . '/';

 return $db;

 }

1.1、 運行時數(shù)據(jù)模型
運行時生成數(shù)據(jù)模型由Structure::model這個方法處理

 static function model($className, $app)

 {

 //父類名,使用PDO鏈接對應的父類名為Dpdo

 $driver = "D" . DRIVER;

 $rumtimeModelPath = PROJECT_PATH . "runtime/models/" . TMPPATH;

 if ($app == "") {

 // 數(shù)據(jù)模型類源碼的位置:eg ./test/models/article.class.php,用戶可以自定義數(shù)據(jù)模型保存在該位置

 $src = APP_PATH . "models/" . strtolower($className) . ".class.php";

 // 數(shù)據(jù)模型父類源碼的位置(___表示占位符,后面會有替換步驟) eg ./test/models/___.class.php

 $psrc = APP_PATH . "models/___.class.php";

 // 運行時數(shù)據(jù)模型類名稱,規(guī)則為原始類名添加"Model"后綴

 $className = ucfirst($className) . 'Model';

 // 運行時數(shù)據(jù)模型父類名稱(___表示占位符,后面會有替換步驟)

 $parentClass = '___model';

 // 運行時保存的數(shù)據(jù)模型類位置 /Users/aron/git-repo/PhpLearning/Foundation/26-brophp/runtime/models/Foundation_26-brophp_test_php/articlemodel.class.php

 $to = $rumtimeModelPath . strtolower($className) . ".class.php";

 // 運行時保存的數(shù)據(jù)模型父類位置 eg /Users/aron/git-repo/PhpLearning/Foundation/26-brophp/runtime/models/Foundation_26-brophp_test_php/___model.class.php

 $pto = $rumtimeModelPath . $parentClass . ".class.php";

 } else {

 $src = PROJECT_PATH . $app . "/models/" . strtolower($className) . ".class.php";

 $psrc = PROJECT_PATH . $app . "/models/___.class.php";

 $className = ucfirst($app) . ucfirst($className) . 'Model';

 $parentClass = ucfirst($app) . '___model';

 $to = $rumtimeModelPath . strtolower($className) . ".class.php";

 $pto = $rumtimeModelPath . $parentClass . ".class.php";

 }

 // 如果有原model存在,用戶自定義了數(shù)據(jù)模型類

 if (file_exists($src)) {

 $classContent = file_get_contents($src);

 $super = '/extendss+(.+?)s*{/i';

 // 如果已經(jīng)有父類

 if (preg_match($super, $classContent, $arr)) {

 $psrc = str_replace("___", strtolower($arr[1]), $psrc);

 $pto = str_replace("___", strtolower($arr[1]), $pto);

 if (file_exists($psrc)) {

 if (!file_exists($pto) || filemtime($psrc) > filemtime($pto)) {

 $pclassContent = file_get_contents($psrc);

 $pclassContent = preg_replace('/classs+(.+?)s*{/i', 'class ' . $arr[1] . 'Model extends ' . $driver . ' {', $pclassContent, 1);

 file_put_contents($pto, $pclassContent);

 }

 } else {

 Debug::addmsg("<font color='red'>文件{$psrc}不存在!</font>");

 }

 $driver = $arr[1] . "Model";

 include_once $pto;

 }

 if (!file_exists($to) || filemtime($src) > filemtime($to)) {

 $classContent = preg_replace('/classs+(.+?)s*{/i', 'class ' . $className . ' extends ' . $driver . ' {', $classContent, 1);

 // 生成model

 file_put_contents($to, $classContent);

 }

 } else {

 // 數(shù)據(jù)模型不存在,用戶沒有定義對應的數(shù)據(jù)模型,如果沒有生成,則生成該數(shù)據(jù)模型

 if (!file_exists($to)) {

 // 繼承Driver對應的父類,PDO的父類為Dpdo,MySQLi的父類為Dmysqli

 $classContent = "<?phpntclass {$className} extends {$driver}{nt}";

 // 運行時生成model

 file_put_contents($to, $classContent);

 }

 }


 // 包含數(shù)據(jù)模型類,返回數(shù)據(jù)模型的類名

 include_once $to;

 return $className;

 }

1.2、 獲取數(shù)據(jù)庫結構信息

獲取數(shù)據(jù)模型對應的數(shù)據(jù)庫表的字段以及其他表信息由setTable該方法處理,不同的數(shù)據(jù)驅(qū)動程序處理數(shù)據(jù)庫操作的方法是不同的,所以對應的數(shù)據(jù)庫驅(qū)動類需要重寫該方法,下面是PDO驅(qū)動對應的setTable方法

 /**

 * 自動獲取表結構

 */

 function setTable($tabName)

 {

 $cachefile = PROJECT_PATH . "runtime/data/" . $tabName . ".php";

 $this->tabName = TABPREFIX . $tabName; //加前綴的表名


 if (!file_exists($cachefile)) {

 try {

 $pdo = self::connect();

 $stmt = $pdo->prepare("desc {$this->tabName}");

 $stmt->execute();

 $auto = "yno";

 $fields = array();

 while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {

 if ($row["Key"] == "PRI") {

 $fields["pri"] = strtolower($row["Field"]);

 } else {

 $fields[] = strtolower($row["Field"]);

 }

 if ($row["Extra"] == "auto_increment")

 $auto = "yes";

 }

 //如果表中沒有主鍵,則將第一列當作主鍵

 if (!array_key_exists("pri", $fields)) {

 $fields["pri"] = array_shift($fields);

 }

 if (!DEBUG)

 file_put_contents($cachefile, "<?php " . json_encode($fields) . $auto);

 $this->fieldList = $fields;

 $this->auto = $auto;

 } catch (PDOException $e) {

 Debug::addmsg("<font color='red'>異常:" . $e->getMessage() . '</font>');

 }

 } else {

 $json = ltrim(file_get_contents($cachefile), "<?ph ");

 $this->auto = substr($json, -3);

 $json = substr($json, 0, -3);

 $this->fieldList = (array)json_decode($json, true);

 }

 Debug::addmsg("表<b>{$this->tabName}</b>結構:" . implode(",", $this->fieldList), 2); //debug

 }

2、 查詢

$article->query("SELECT * FROM article", "select");代碼執(zhí)行的是查詢的功能,查詢方法是最基礎的方法,上層的total()、select()、find()、insert()、update()、delete() 等數(shù)據(jù)庫操作的方法都依賴于該方法的處理,不同的數(shù)據(jù)驅(qū)動程序處理數(shù)據(jù)庫操作的方法是不同的,所以對應的數(shù)據(jù)庫驅(qū)動類需要重寫該方法,下面是PDO驅(qū)動對應的query方法

/**
* 執(zhí)行SQL語句的方法
* @param string $sql 用戶查詢的SQL語句
* @param string $method SQL語句的類型(select,find,total,insert,update,other)
* @param array $data 為prepare方法中的?參數(shù)綁定值
* @return mixed 根據(jù)不同的SQL語句返回值
*/
function query($sql, $method, $data = array())
{
$startTime = microtime(true);
$this->setNull(); //初使化sql
?
$value = $this->escape_string_array($data);
$marr = explode("::", $method);
$method = strtolower(array_pop($marr));
if (strtolower($method) == trim("total")) {
$sql = preg_replace('/select.*?from/i', 'SELECT count(*) as count FROM', $sql);
}
$addcache = false;
$memkey = $this->sql($sql, $value);
if (defined("USEMEM")) {
global $mem;
if ($method == "select" || $method == "find" || $method == "total") {
$data = $mem->getCache($memkey);
if ($data) {
return $data; //直接從memserver中取,不再向下執(zhí)行
} else {
$addcache = true;
}
}
}
?
try {
$return = null;
$pdo = self::connect();
$stmt = $pdo->prepare($sql); //準備好一個語句
$result = $stmt->execute($value); //執(zhí)行一個準備好的語句
?
//如果使用mem,并且不是查找語句
if (isset($mem) && !$addcache) {
if ($stmt->rowCount() > 0) {
$mem->delCache($this->tabName); //清除緩存
Debug::addmsg("清除表<b>{$this->tabName}</b>在Memcache中所有緩存!"); //debug
}
}
?
switch ($method) {
case "select": //查所有滿足條件的
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
?
if ($addcache) {
$mem->addCache($this->tabName, $memkey, $data);
}
$return = $data;
break;
case "find": //只要一條記錄的
$data = $stmt->fetch(PDO::FETCH_ASSOC);
?
if ($addcache) {
$mem->addCache($this->tabName, $memkey, $data);
}
$return = $data;
break;
?
case "total": //返回總記錄數(shù)
$row = $stmt->fetch(PDO::FETCH_NUM);
?
if ($addcache) {
$mem->addCache($this->tabName, $memkey, $row[0]);
}
?
$return = $row[0];
break;
case "insert": //插入數(shù)據(jù) 返回最后插入的ID
if ($this->auto == "yes")
$return = $pdo->lastInsertId();
else
$return = $result;
break;
case "delete":
case "update": //update
$return = $stmt->rowCount();
break;
default:
$return = $result;
}
$stopTime = microtime(true);
$ys = round(($stopTime - $startTime), 4);
Debug::addmsg('[用時<font color="red">' . $ys . '</font>秒] - ' . $memkey, 2); //debug
return $return;
} catch (PDOException $e) {
Debug::addmsg("<font color='red'>SQL error: " . $e->getMessage() . '</font>');
Debug::addmsg("請查看:<font color='#005500'>" . $memkey . '</font>'); //debug
}
}

分享到:
標簽:MVC
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定