PHP 程式設計進階(重點是面向物件和MVC)
類是描述一類事物的抽象名稱
class 類名{ 類的描述 }
物件是一個具體的事物,他必然隸屬於某個類
$obj = new 類名();
示例程式碼:
<?php class Dog{ var $color = ""; function speak(){ echo "wangwang"; } } $dog1 = new Dog(); $dog1 -> color = "red"; $dog1 -> speak();
2.屬性和方法:
屬性本質就是變數,只不過失去了自由,現在只能被這個類或者這個類例項化的物件訪問 物件 -> 屬性,用於描述這個類的一些共同的特徵資訊
方法本質就是函式,只不過失去了自由,現在只能被這個類或者這個類例項化的物件訪問 物件 -> 方法,用於描述這個類的一些共同的行為動作
3.物件的建立形式:
1.方法一:
$obj = new 類名();
2.方法二:
$a = "類名"; $obj = $a();
這就是我們所說的“可變類”
3. 方法三:
$obj = new 類名(); $obj1 = new $obj();
這個就比較神奇了,我們用一個物件去建立了這個物件所屬類的另一個物件
4.方法四:
$obj = new self;
建立本類
4.物件的使用:
使用屬性就將其看成是變數,可以取值賦值或者 unset()、 isset()
使用方法就是一個函式
5.物件的值傳遞
我們知道變數的傳值是值傳遞,只有在使用了& 符號以後才是引用傳遞,那麼我們來做一個實驗:
示例程式碼:
<?php class Dog{ var $p1 =1; } $t1 = new Dog(); $t2 = $t1; echo "t1中的p1 ".$t1->p1."<br>"; echo "t2中的p1 ".$t2->p1."<br>"; $t1->p1 = 11; echo "賦值後t1中的p1 ".$t1->p1."<br>"; echo "賦值後t2中的p1 ".$t2->p1."<br>";
結果:
t1中的p1 1 t2中的p1 1 賦值後t1中的p1 11 賦值後t2中的p1 11
我們發現好像並不是這樣了,這是為什麼呢?
解釋:
物件的的賦值和普通變數的賦值是有差別的,我們在普通變數賦值的時候這個變數是直接拿到的值,但是物件賦值傳遞的是 編號 ,(我們在生成一個新的物件的時候本省就不是將物件直接給變數,而是將物件的編號賦值給變數,然後變數通過這個編號間接地操縱這個物件,這個編號能通過 var_dump() 看到,但是並不能選擇,因此如果我們兩個變數拿到的都是同一個編號的話自然他們操縱的就是同一個變量了,我們有上面的結果也就不奇怪了)
如下圖所示:
那我們使用引用傳遞呢?
示例程式碼:
<?php class Dog{ var $p1 =1; } $t1 = new Dog(); $t2 = $t1; echo "t1中的p1 ".$t1->p1."<br>"; echo "t2中的p1 ".$t2->p1."<br>"; $t1->p1 = 11; echo "賦值後t1中的p1 ".$t1->p1."<br>"; echo "賦值後t2中的p1 ".$t2->p1."<br>"; $t2 = &$t1; $t1->p1 = 111; echo "賦值後t1中的p1 ".$t1->p1."<br>"; echo "賦值後t2中的p1 ".$t2->p1."<br>";
結果:
t1中的p1 1 t2中的p1 1 賦值後t1中的p1 11 賦值後t2中的p1 11 賦值後t1中的p1 111 賦值後t2中的p1 111
那麼賦值的示意圖是什麼樣子的呢?
如圖所示:
結論:
對於物件來講,傳遞的都是編號,操縱的也都是編號,如果我們unset() 一個變數,只是物件和編號之間的連線斷了,並不影響另一個變數,但是如果我們給引用賦值的物件賦值一個數字,這樣就相當於斷了編號與原始物件之間的聯絡,由於引用賦值,用的是一條線,那麼另一個也不能用了,但是直接賦值由於是獨立的兩條線就沒有影響。
6.靜態屬性和靜態方法
靜態屬性和靜態方法是隻隸屬於類的屬性和方法,應該通過類來呼叫
定義格式:
static 屬性名[=xxx];
static function 方法名(){xxx};
訪問格式:
類名::$屬性名 類名::方法名
我們有了靜態屬性和靜態方法,呼叫的時候就不必new 物件了,可以直接使用類名呼叫
示例程式碼:
<?php class Dog{ static $p1 =1; static function hello(){ return "helo world"; } } echo Dog :: hello()."<br>"; echo Dog :: $p1;
結果:
helo world 1
7.this 和 self 關鍵字
$this 代表當前類的物件
self 代表類本身
如果你學過Python 的面向物件的話,這裡的 this 就相當於 python 中的 self 這裡的 self 就是 python 中的 cls
self 在類內部改變靜態變數的值很有用
$this 不能用在靜態方法中,因為呼叫靜態方法的是類而不是類物件
8.類常量
就是常量,只能放在一個類中,只能用該類去呼叫,並且這個常量在宣告的時候必須賦值
class 類名{ const 常量名 = 常量值; }
9.構造方法
1.概念:
就是在一個類進行例項化的時候會自動呼叫的方法,使用一個固定的名字 __construct
構造方法通常是用來簡化我們物件屬性的初始化工作的
10.析構方法
1.概念:
就是在一個物件被銷燬的時候自動呼叫的方法,使用一個固定的名字 __destruct
2.那麼什麼時候物件會被銷燬呢?
(1)當網頁程式碼執行結束的時候,所有的物件都會被銷燬,(變數會按照生成的順序逆序的銷燬)
(2)當一個物件沒有變數引用的時候(引用計數機制)
二、類的繼承
1.基本概念:
如果一個類B 自動擁有了另一個類 A 的特徵資訊,那麼我們就說 B 繼承了 A
示例程式碼:
<?php class A{ function speak(){ echo "wangwang"."<br>"; } } class B extends A{ function move(){ echo "i can move<br>"; } } $dog = new B(); $dog->speak(); $dog->move();
結果:
wangwang i can move
2.派生
派生是繼承的另一個角度的說法,比如 B 繼承了 A, 那麼就說 A 派生了 B
3.單繼承
PHP 和大多數的面向物件的語言都是單繼承模式,C++ 支援多繼承, Python 也支援多繼承
4.訪問控制修飾符
修飾符就是放在一個屬性或者方法的前面用來表明這個屬性或者方法的可訪問程度的關鍵字。在 php 中只有三個
public : 誰都能訪問,var 在修飾屬性的時候和 public 是一樣的
protected : 只有自己家族內部可以訪問(具有繼承關係的多個類之間)
private : 只有自己可以訪問
注意:
對於屬性必須使用修飾符
對於方法可以省略修飾符,省略預設為public
示例程式碼:
<?php class Person{ public $name; protected $age; private $password; function __construct($name,$age,$pass){ $this->name = $name; $this->age = $age; $this->password = $pass; } } $xiaoming = new Person("小明",18,"123456"); echo $xiaoming->name; echo $xiaoming->age; echo $xiaoming->password;
結果:
這段程式碼只能打印出一個小明,然後就會報錯
這驗證了我們的修飾符的作用,我們想要訪問只能讓他自己和我們說
示例程式碼:
<?php class Person{ public $name; protected $age; private $password; function __construct($name,$age,$pass){ $this->name = $name; $this->age = $age; $this->password = $pass; } function showInfo(){ echo $this->name."<br>"; echo $this->age."<br>"; echo $this->password; } } $xiaoming = new Person("小明",18,"123456"); $xiaoming->showInfo();
結果:
小明 18 123456
同樣如果我們使用一個類去繼承這個 Person 類,我麼還是這樣訪問,我們就會發現沒法打印出password ,因為是 private 的只能自己類訪問
5.構造方法和析構方法在繼承中的表現
如果子類沒有就會自動呼叫父類的
如果子類有就呼叫自己的,但是我們能在子類的方法中人為的呼叫父類的,形式為: parent :: 對應父類方法
示例程式碼:
<?php class A{ function __construct(){ echo "父類A的構造方法<br>"; } } class B extends A{ function __construct(){ echo "子類B的構造方法<br>"; parent :: __construct(); } } $b = new B();
結果:
子類B的構造方法 父類A的構造方法
6.parent 關鍵字
parent 關鍵字用來表示某一個類的父類(或者說父類的物件),類似於Python 中的 super(),常常在子類中去訪問父類的方法或者屬性,他的使用形式只有一個
parent :: 父類的屬性或者方法
常常用於子類不想重寫父類已經出現過得構造方法,就用這個避免重寫,只要新增新的就可以了
示例程式碼:
<?php class Person{ public $name = " "; public $age = " "; function __construct($name,$age){ $this -> name = $name; $this -> age = $age; } function showInfo(){ echo "xxxx"; echo "yyyy"; } } class Teacher extends Person{ public $edu; function __construct($name, $age ,$edu) { parent::__construct($name, $age); $this -> edu = $edu; } function showInfo() { parent::showInfo(); // TODO: Change the autogenerated stub echo "zzzz"; } }
7.重寫
重寫就是子類重新定義父類繼承給自己的屬性或者方法
1.重寫的要求
(1)子類重寫上級類成員時,訪問控制修飾符不能許可權更低(意思是可以更開放)
父類: public 子類: public
父類: protected 子類: protected/public
父類: private 子類: 不能重寫
(2) 子類重寫父類的方法是要求形參保持一致
8.final class 和 final method
最終類:定義一個類,這個類不允許別的類去繼承
最終方法:定義一個方法,這個方法不允許下級類去重寫
三、設計模式
1.什麼叫設計模式
是面向物件程式設計中“常見任務”中的程式碼模式的經驗總結
2.工廠模式
工廠模式就是設計這樣一個類(F),該類可以接受一個引數,這個引數代表某個類名(B),然後這個類(F)就能生成所傳入的類(B)所對應的物件
可見工廠類的目的就是生產各種不同類的物件
示例程式碼:
<?php class Factory{ static function getObject($class_name){ $obj = new $class_name(); return $obj; } }
3.單例模式
設計一個類,讓這個類只能得到一個單例物件,那麼這個類就叫做單例類,生成出來的物件就叫做單例物件
那麼怎麼實現呢?我們的想法就是,我們自定義一個例項化的介面,並且在介面中做判斷,這樣就能控制只能例項化一次
示例程式碼:
<?php class Single{ static $s = null; function __construct(){ } function getOne(){ if(empty(self::$s)){ self::$s = new self(); return self::$s; } else{ self::$s; } } }
四、抽象類和抽象方法
1.抽象類
1.概念:
抽象類就是一個不能例項化的類
形式:
abstruct class 類名{ 類成員 }
2.不能例項化,那麼抽象類有什麼作用?
用於定義一些類的共同上級類,讓這些類都具有某種共同的特徵(其實就是強制子類實現某種屬性或者方法)
2.抽象方法
抽象方法是一個什麼都不做的方法,只有函式頭沒有函式體,形式:
abstruct function 方法名 (形參);
和抽象類類似,抽象方法主要用於規定子類一定要實現的方法,但是沒有規定怎麼實現
3.抽象類和抽象方法的關係
(1)一個類中有抽象方法那麼這個類必須宣告為抽象類
(2)一個類繼承一個抽象類那麼就必須實現所有的抽象方法,除非這個類也是作為一個抽象類
(3)子類實現父類的抽象方法的時候訪問控制修飾符許可權不能降低(可以更加開放),並且形參需要一致
五、過載技術 overloading
1.概念
php 中的過載指的是,當我們使用物件(或者類)去訪問一些不存在的屬性或者方法的時候,就會使用某些預先定義好的特殊方法來應對這種情況
可見PHP 的過載是內部為了應對非法使用屬性或者方法的措施
2.過載的分類
1.屬性過載
2.方法過載
3.屬性過載:
屬性就是變數,於是屬性也就有和變數一樣的四種操作 取值 賦值 isset()判斷 unset()銷燬
於是,屬性過載就是在類中預先定義了四種特殊方法,來應對這四種對屬性的可能錯誤的操作
__set($name,$value) __get($name) __isset($name) __unset($name)
1. __set($name,$value)
在給一個不存在的屬性賦值時候會自動呼叫,$name 會自動賦值為那個不存在的屬性,$value 會賦值為那個不存在的屬性的值,我們就能利用這個特性實現動態屬性(用什麼就實現什麼,無需提前定義)
示例程式碼:
<?php class A{ public $p1 = 1; public $prop_list = array(); function __set($name, $value) { // TODO: Implement __set() method. $this->prop_list[$name] = $value; } } $a = new A(); $a->p1 = 11; $a->p2 = 22; var_dump($a);
結果:
object(A)[1] public 'p1' => int 11 public 'prop_list' => array (size=1) 'p2' => int 22
2. __get($name)
在給一個不存在的屬性取值時候會自動呼叫
示例程式碼:
<?php class A{ public $p1 = 1; public $prop_list = array(); function __set($name, $value) { // TODO: Implement __set() method. $this->prop_list[$name] = $value; } function __get($name) { // TODO: Implement __get() method. if(!empty($this->prop_list[$name])) { return $this->prop_list[$name]; }else{ return "該屬性不存在"; } } } $a = new A(); $a->p1 = 11; $a->p2 = 22; echo $a->p2;
結果:
3. __isset($name)
對一個不存在的屬性使用 isset() 方法的時候呼叫
示例程式碼:
class A{ public $p1 = 1; public $prop_list = array(); function __set($name, $value) { // TODO: Implement __set() method. $this->prop_list[$name] = $value; } function __get($name) { // TODO: Implement __get() method. if(!empty($this->prop_list[$name])) { return $this->prop_list[$name]; }else{ return "該屬性不存在"; } } function __isset($name) { // TODO: Implement __isset() method. if(isset($this->prop_list[$name])){ return true; }else{ return false; } } } $a = new A(); $a->p1 = 11; $a->p2 = 22; echo isset($a->p2);
結果:
4. __unset($name)
對一個不存在的屬性使用 unset() 方法的時候呼叫
示例程式碼:
<?php class A{ public $p1 = 1; public $prop_list = array(); function __set($name, $value) { // TODO: Implement __set() method. $this->prop_list[$name] = $value; } function __get($name) { // TODO: Implement __get() method. if(!empty($this->prop_list[$name])) { return $this->prop_list[$name]; }else{ return "該屬性不存在"; } } function __isset($name) { // TODO: Implement __isset() method. if(isset($this->prop_list[$name])){ return true; }else{ return false; } } function __unset($name) { // TODO: Implement __unset() method. if(isset($this->prop_list[$name])){ unset($this->prop_list[$name]); }else{ echo "error"; } } } $a = new A(); $a->p1 = 11; $a->p2 = 22; unset($a->p2);
4.方法過載:
方法過載涉及到兩個函式 call() callstatic()
call($name,$arguments)
當對一個類未定義的靜態方法進行呼叫的時候會自動呼叫
callstatic($name,$arguments)$name 不存在的函式名 $arguments 所有引數組成的陣列
1. __call($name,$arguments)
示例程式碼:
<?php class A{ function __call($name, $arguments) { // TODO: Implement __call() method. if($name == "eat"){ $num = count($arguments); if($num ==1){ $this->hezhou($arguments[0]); } if($num ==2){ $this->chifan($arguments[0],$arguments[1]); } } } function hezhou($zhou){ echo "zheng zai he $zhou <br>"; } function chifan($fan,$tools){ echo "zheng zai yong $tools chi $fan <br>"; } } $p = new A(); $p->eat("zhou"); $p->eat("fan","kuaizi");
結果:
zheng zai he zhou zheng zai yong kuaizi chi fan
2. __callstatic($name,$arguments)
這個完全類似,我就不重複講了
六、介面
1.概念:什麼是介面
介面是比抽象類更抽象的一種類似類的結構,介面中只有兩種成員,一種是常量,另一種是抽象方法
形式:
interface class A{ const PI = 3.14; function B(); //介面中的方法都是抽象方法,不用寫 abstract }
2.為什麼需要介面
面向物件的單繼承是對現實世界多繼承現象的一種妥協(為了不使的程式碼過於複雜),但是還是不免有多繼承的情形需要描述,於是介面技術就成了對這種妥協的一種彌補(介面能夠實現多繼承),只不過我們隊介面的繼承換了一個名字叫做“實現”—> implements
class 類名 implements 介面名{ 成員定義 }
示例程式碼:
<?php interface Player{//音樂播放器介面 function play(); function next(); function prev(); function stop(); } interface USBset{//USB介面 const WIDTH = 12; const HEIGHT = 5; function data_in(); function data_out(); } class MP3Player implements Player,USBset{ function play(){} function next(){} function prev(){} function stop(){} function data_in(){} function data_out(){} }
3.關於介面的其他細節
1.一個類在實現介面的同時也能繼承父類
2.介面之間也可以相互繼承
3.介面中的常量和抽象方法只能是 Public 無需寫 abstruct
七、MVC模式
1.專案設計的基本流程
1.需求分析
人員:專案經理,技術總監
目標:寫出專案需求說明書
2.專案概要和詳細設計
人員:專案經理,技術總監
目標:概要設計說明書和詳細設計說明書
3.介面設計
人員: 設計師(美工)
目標:介面設計效果圖
4.前端頁面製作
人員:前端工程師
目標:html css js
5.前後臺功能實現
人員:軟體工程師
目標:php 程式碼
6.功能測試
人員:測試工程師
目標:測試功能,反饋問題並最終得到可用產品
7.釋出上線,執行維護
人員:運維人員的工作
目標:保證系統的正常執行
2.顯示與邏輯相分離的思想
需求:
顯示當前時間,要求有三種顯示形式:
1.顯示年月日
2.顯示時分秒
3.兩者都 顯示
1.顯示與邏輯混合
如果我們想實現這個功能寫成一個頁面應該是非常簡單的,程式碼如下:
示例程式碼:
<html> <body> <p align = right> <a href="?type=1">形式一</a> <a href="?type=2">形式一</a> <a href="?type=3">形式一</a> <hr> </p> <?php if(!empty($_GET['type']) && $_GET['type'] == "1"){ $t1 = date("Y年m月d日"); }elseif(!empty($_GET['type']) && $_GET['type'] == "2"){ $t1 = date("H:i:s"); }else{ $t1 = date("Y年m月d日 H:i:s"); } echo "<h1>$t1</h1>"; ?> </body> </html>
2.顯示與邏輯相分離
我們可以將顯示與邏輯放到兩個檔案中去
PHP 檔案
show-time.php <?php if(!empty($_GET['type']) && $_GET['type'] == "1"){ $t1 = date("Y年m月d日"); }elseif(!empty($_GET['type']) && $_GET['type'] == "2"){ $t1 = date("H:i:s"); }else{ $t1 = date("Y年m月d日 H:i:s"); } include "./show-time.html"; ?>
HTML檔案
show-time.html <html> <body> <p align = right> <a href="?type=1">形式一</a> <a href="?type=2">形式一</a> <a href="?type=3">形式一</a> <hr> </p> <?php echo "<h1>$t1</h1>"; ?> </body> </html>
這樣依然可以執行
3.模板技術
在很多的網站應用中,都要實現這樣一種需求:整體上功能不變,但是介面經常要更換為不同的風格樣式
在顯示與邏輯相分離的技術基礎上,做成多分不同的 HTML ,再通過使用者的選擇更換HTML來顯示,那這些HTML 就構成了模板
3.MVC框架原理
1.概念:
M: Model 模型
V: View 檢視
C:Controller 控制器
2.MVC 的簡單演示
我們假設求時間是一個非常複雜的工作,就像真實專案中的取資料要呼叫資料庫模組一樣,於是將求時間的部分抽象成 model 模組,通過 controller 模組呼叫 Model 來實現求時間的功能,然後再將結果放到 view 模組中
示例程式碼:
show-time-controller.php
<?php require_once "show-time-model.php"; if(!empty($_GET['type']) && $_GET['type'] == "1"){ $obj = new GetTimeModel(); $t1 = $obj->GetDate(); }elseif(!empty($_GET['type']) && $_GET['type'] == "2"){ $obj = new GetTimeModel(); $t1 = $obj->GetTime(); }else{ $obj = new GetTimeModel(); $t1 = $obj->GetDateTime(); } include "./show-time-view.html"; ?>
後面我們會將其改成一個類,根據傳入的不同引數呼叫這個類的不同方法
show-time-model.php
<?php class GetTimeModel{ function GetDate(){ return Date("Y年m月d日"); } function GetTime(){ returnDate("H:i:s"); } function GetDateTime(){ return Date("Y年m月d日 H:i:s"); } }
show-time-view.html
<html> <body> <p align = right> <a href="?type=1">形式一</a> <a href="?type=2">形式一</a> <a href="?type=3">形式一</a> <hr> </p> <?php echo "<h1>$t1</h1>"; ?> </body> </html>
4.MVC思想框架
如圖所示:
解釋:
1.瀏覽器直接請求的是控制器檔案,也只有控制器檔案知道使用者給了什麼(請求資料)以及使用者真正要的是什麼(目標)
2.控制器根據使用者的請求做兩件事
(1)呼叫哪個模型
(2)獲取什麼資料
(3)顯示資料到哪個檢視中(其實就是載入檢視檔案)
3.模型檔案:只根據控制器的呼叫生產資料並返回給控制器
4.檢視檔案:只負責顯示資料(資料顯示在頁面的哪裡以及顯示的效果),並且是由控制器決定顯示哪些資料
5.模型檔案和檢視檔案沒有直接的關係
如下圖所示:
再直觀一點我們可以看一下類比圖
4.Model 層的典型實現
1.模型層的功能與典型的程式碼模式
class ModelDemo{ function f1(){ $result = 獲取資料庫中的資料1; return $result; } function f2(){ $result = 獲取資料庫中的資料2; return $result; } ... }
2.控制器層的功能與典型的程式碼模式
1.載入模型類檔案
2.對模型類例項化以獲得相應的物件
3.呼叫模型類物件的方法以獲得相應的資料(不同的方法能獲得不同的資料)
require_once "模型檔案" class xxxController{ function xxxAction(){ $obj = new 模型類(); $res1 = $obj->方法1(); } function yyyAction(){ $obj = new 模型類(); $res2 = $obj->方法2(); } ... } $controller = new xxxController(); $action = !empty($_GET['action']) ? $_GET['action'] : "Index"; $action = $action."Action"; $controller->$action();
我們對模型檔案和模型類命名有如下習慣
類定義:
class xxxModel{ ... }
檔名:
xxxModel.class.php
3.模型類的單例工廠
我們在之前的操作中都是每一個控制器的每一個方法都會例項化一個模型類,這在我們看來是沒有必要的,一個模型類就能實現所有的功能了,於是我們利用之前學過的技術,建立一個模型類的單例工廠,實現我們只要傳入我們想要例項化的模型類就能得到該模型類的例項化物件,並且,這個物件只會建立一次。
示例程式碼:
ModelFactory.class.php
class ModelFactory{ static $arry = array(); static function M($class_name){ if(empty(self::$array[$class_name])){ self::$array[$class_name] = new $class_name(); } return self::$array[$class_name]; } }
我們只要將其包含到 xxxController.class.php 檔案裡面就可以了,從而可以代替上面程式碼中的 $obj = new 模型類(); 這一句話
4.整個模型層的類庫結構圖
在應用中通常每個資料表(table)都要使用一個模型類檔案xxxModel ,來對這個表所需的資料進行相應的操作,比如使用者表:註冊、刪除、登入、修改密碼、修改常規資訊、顯示所有使用者、檢視單個使用者資訊
即,模型層和資料庫中的表有如下大致關係
如圖所示:
5.Controller 層的典型實現
1.控制器類的細節
1.功能
用於獲取使用者的請求資料,根據使用者的資料來選擇控制器類對應的方法,這個方法會例項化模型類,然後呼叫對應的方法,獲取資料,並再是圖中顯示
2.劃分:
控制器通常按照應用的模組(功能組)進行劃分,一個控制對應一個模組(頁面)的不同的操作,比如使用者介面的增刪改查,實際上可以看成是一個模組,使用一個控制器(裡面針對不同的功能實現不同的方法),商品列表的各種操作可以看成是一個模組,使用另一個控制器。
3.與模型的區別:
通常模型是嚴格按照表進行劃分的,一個表對應一個模型類,對一個表進行各種的操作
4.動作
動作是什麼呢? 動作就是使用者在網頁上所做的能跟伺服器打交道的行為(比如點選連結或者提交表單)
在程式碼級別,頁面上的任何一個動作都對應著控制器中的一個方法
我們可以通過傳參的方式進行動作的選擇,這裡有一個點可以優化,就是如果我們將傳參的值和控制器的類的方法名稱對應起來我們就能實現一行程式碼解決這個選擇問題,並且擴充套件也非常的方便。
2.基礎控制器類
為什麼需要基礎控制器類,因為我們想統一設定所有控制器中的一些東西,比如編碼和某些都需要功能,於是我們想要建立一個所有控制器的上級,這個上級類就是基礎控制器類,或者說是控制器基類。
6.View 層的典型實現
1.檢視層的功能:
展示頁面的靜態內容以及相關的變數資料
2.資料的分類:
(1)普通標量資料
<?php echo "xx"?>、
(2)陣列資料
一維陣列:
<?php echo $arr['xxx']; ?>
二維陣列:
<?php foreach ($arr_list as $key=>$arr){ ?> <?php echo $arr['欄位1']; ?> <?php echo $arr['欄位2']; ?> <?php echo $arr['欄位3']; ?> <?php echo $arr['欄位4']; ?> <?php } ?>
(3)物件資料:
<?php echo $obj->屬性?>
八、關於 MVC 專案的其他常見做法
1.請求分發器(前端控制器的實現)
我們發現我們很多的控制器命名規則以及他的例項化的方法都是一樣的,比如 UserController 和 ProductController ,於是我們就想能不能將其抽象出來,我們想尋找一個變量表示 User 和 Product ,並且這個變數也就能表示這個模組(因為我們當時約定的命名規則就是模組名加 Controller),將這個模組的選擇權交給使用者
我們從每個控制器中抽象出來一部分,放在一個Index.php 中
index.php
require_once "./ModelFactory.class.php"; require_once "./BaseController.class.php"; $ctrl = !empty($_GET['ctrl']) ? $_GET['ctrl'] : "User"; require_once "./{$ctrl}Model.class.php"; require+once "./{$ctrl}Controller.class.php"; $ctrl_name = $ctrl."Controller"; $controller = new $ctrl_name(); $action = !empty($_GET['action']) ? $_GET['action'] : "Index"; $action = $action."Action"; $controller->$action();
這個檔案寫好以後,在每個控制器中的下面這部分程式碼就不需要了,就會變得非常的乾淨
require_once "./ModelFactory.class.php"; require_once "./BaseController.class.php"; $ctrl = !empty($_GET['ctrl']) ? $_GET['ctrl'] : "User"; require_once "./{$ctrl}Model.class.php"; require+once "./{$ctrl}Controller.class.php"; $controller = new $ctrl_name(); $action = !empty($_GET['action']) ? $_GET['action'] : "Index"; $action = $action."Action"; $controller->$action();
2.目錄結構的設定
我們一個專案不可能只有一個資料夾,那樣的話檔案太多太雜沒法看,非常不利於後期的維護,於是我們需要對檔案進行按照類別的劃分
站點根目錄/
/Models /Controllers /Views /Bases index.php
九、PDO 資料物件
1.概念:
PDO 是已經寫好的資料庫工具類,通過他能對資料庫進行各種操作,非常的方便快捷
2.特點:
(1)他能操縱各種的資料庫 ,mysql oracle sybase…
(2)他能實現除了增刪改查以外的更多功能,比如事務
(3)他對不同的資料庫有著統一的應用方式,在使用的時候無需考慮不同資料庫SQL語法的細節差異
(4)PDO 實際上是一個類,我們使用的時候就需要new 一個物件出來
3.PHP 程式碼中常見的操作資料庫的情況
(1)連線資料庫得到資料庫的連線資源
(2)執行各種sql 語句得到布林值或者結果集
(3)對結果集的資料進行取用,遍歷 一般就是 fetch
4.PDO 系統的邏輯結構
如圖所示:
要想操作不同的資料庫,就要在 php.ini 中開啟對應的PDO模組
5.POD 使用
1.連線資料庫
$DSN = "mysql: host=伺服器地址;port=埠號;dbname=資料庫名"; $Options = array(PDO::MYSQL_ATTR_INIT_COMMADN => 'set names utf8'); $pdo = new pdo($DNS,使用者名稱,密碼,$Options);
DSN : Data Source Name
2.執行SQL語句
$result1 = $pdo->exec(增刪改語句); $result2 = $pdo->query(各種sql語句);
exec 習慣上執行沒有返回結果集的語句,返回值為 受影響的行數,當然也可能返回false
query 執行select 這種有返回結果集的語句,執行失敗返回false,成功的話返回的結果集還需要進一步的處理。
3.斷開連線
$pdo = null;
6.POD 的錯誤處理
PDO 的錯誤處理有兩種模式:
(1)靜默模式:
發生錯誤以後並不會產生任何提示,需要人為的通過程式碼獲取
示例程式碼:
$pdo->exec($sql); $code = $pdo->errorCode();//獲取上一行程式碼執行的錯誤,如果沒有錯誤則返回0、 if($code == 0){ echo "執行成功"; } else{ $info = $pdo->errorInfo(); echo "失敗,錯誤代號:".$info[2]; }
(2)異常模式:、
示例程式碼:
try{ $pdo->exec($sql); } catch(Exception $e){ echo "發生錯誤,請參考錯誤提示:".$e->GetMessage(); }
7.POD 的結果集物件
1.得到結果集物件:
$res = $pdo->query("select ...");
2.常見處理方法
得到行數
$res->rowCount();
得到列數
$res->columnCount();
返回一行資料(結果是一維陣列)
$res->fetch(返回型別)
返回型別:
PDO::FETCH_ASSOC 返回關聯陣列
PDO::FETCH_NUM 返回索引陣列
PDO::FETCH_BOTH 返回前兩者皆有的資料(預設值)、
PDO::FETCH_OGJ 返回物件
返回所有資料(結果二維陣列)
$res->fetchAll(返回型別);
返回指定的列
$resds->fetchColumn([$i]);
返回第i列
8.POD 結果集物件的預處理語法、
1.為什麼需要預處理
一般的sql 語句一條一條的執行是沒有任何的問題的,但是如果我們希望大量的 sql語句批量的執行的話就會顯得效率不足,於是我們就可以使用預處理語句來提升我們的執行效率,
但是前提是:
這些語句有一定的規律性,其中只有部分引數變化
2.形式:
形式一:佔位符形式
引數的順序一次是 1,2,3,4,5
$sql = "select * from user_list where age = ?";
示例程式碼:
$arr = array(11,28,32); $sql = "select * from user_list where age = ?"; $result = $pdo->prepare($sql); foreach($arr as $value){ $result->bindVaule(1,$value);//如果有多個問號就可以有多個語句 $result->execute(); $result = $rersult->fetch(PDO::FETCH_ASSOC); print_r($result); }
形式二:命名引數形式
$sql = "select * from user_list where age= :v1";
示例程式碼:
$sql = "select * from user_list where age = :v1 and edu = :v2"; $result = $pdo->prepare($sql); $result->bindVaule(":v1",11); $result->bindVaule(":v2","高中"); $result->execute(); $result = $rersult->fetch(PDO::FETCH_ASSOC); print_r($result);