PHP資料庫操作物件導(dǎo)向的優(yōu)點(diǎn)_PHP教程
Jul 21, 2016 pm 04:11 PM
我們都知道如何從Mysql獲取我們需要的行(記錄),讀取數(shù)據(jù),然後訪問一些改動(dòng)。很明顯也很直接,過程背後也沒有什麼拐彎抹角的。然而對(duì)於我們使用面對(duì)物件的程式設(shè)計(jì)(OOP)來管理我們資料庫中的資料時(shí),這個(gè)過程就需要大幅改進(jìn)一下了。這篇文章將對(duì)如何設(shè)計(jì)一個(gè)面對(duì)物件的方式來管理資料庫的記錄做一個(gè)簡單的描述。你的數(shù)據(jù)當(dāng)中的所有內(nèi)部邏輯關(guān)係將被封裝到一個(gè)非常條理的記錄對(duì)象,這個(gè)對(duì)象能夠提供專門(專一)的確認(rèn)代碼系統(tǒng),轉(zhuǎn)換以及數(shù)據(jù)處理。隨著Zend Engine2 和PHP5的發(fā)布,PHP開發(fā)者將擁有更強(qiáng)大的面對(duì)物件的工具來輔助工作,這將使這個(gè)過程(面對(duì)物件地管理資料庫)更有吸引力。
以下列出了一些使用物件來描敘你的資料庫的有利方面:
存取方法(Accessor methods)將會(huì)使你對(duì)屬性的讀取和寫入過程做到完全的控制
每一級(jí)的每個(gè)記錄和屬性(的操作)都有確認(rèn)過程
從關(guān)係表中智能的獲取對(duì)象
重複使用的邏輯方法意味著所有的資料互動(dòng)都要通過相同的基礎(chǔ)程式碼(codebase),這將使維護(hù)變得更加簡單
程式碼簡單,因?yàn)椴煌挠涗浀膬?nèi)部邏輯都已經(jīng)包含在各自所處的類別(class)當(dāng)中,而不是繁瑣的函式庫(lib)檔案
在手工編寫程式碼和SQL查詢語句時(shí),出錯(cuò)的機(jī)會(huì)將更少
存取方法(Accessor methods)
存取方式是透過類別給實(shí)例(instance)的變數(shù)賦值。一個(gè)例子,我有一個(gè)叫User的類,並且有一個(gè)實(shí)例$username,我會(huì)寫這樣的存取方法(函數(shù)),User->username()和User->setUsername()用來傳回和給實(shí)例賦值。
class User {
var $username;
function username() {
return $this->username; ??>}
function setUsername($newUsername) {
$this->username = $newUsername;
}
}
?>
這裡有很好的理由讓我們寫這樣的「特別的程式碼」。它將使開發(fā)者更靈活的改變類別的繁瑣的工作,因?yàn)檫@個(gè)過程將不需要其他的使用類別的php程式碼。讓我們來看看下面這個(gè)更加完善的可信賴的User類別。
變數(shù)$username將不復(fù)存在,所有的東西都被整合的放在數(shù)組$_data當(dāng)中
如果username是空的話,username()函數(shù)將提供一個(gè)缺?。J(rèn))的值給它
setUsername()過程將在接受值之前確認(rèn)username是否合乎標(biāo)準(zhǔn)格式(如字長等)
class User {
var $_data = array(); // associative array containing all the attributes for the User
function username() {
return !empty($this->_data['username']) ? $this-> _data['username'] : '(no name!)';
}
function setUsername($newUsername) {
if ($this->validateUsername($newUsername)) {
$this->_data['username'] = $newUsername;
}
}
function validateUsername(&$someName) {
if (strlen($someName) > 12) {
throw new Exception('Your username is too long'); // PHP5 only
}
return true;
}
}
?>
}
?>
?>
顯而易見,這對(duì)我們控制存取物件的資料有很大幫助。如果一個(gè)程式設(shè)計(jì)師已經(jīng)直接存取username的訊息,以上程式碼的變更將會(huì)破壞他的程式碼。然而我們可以使用(類別的)訪問方法,就像上面程式碼中註釋的那樣,添加一個(gè)驗(yàn)證的功能而不需要改變?nèi)魏纹渌臇|西。注意username的驗(yàn)證(範(fàn)例當(dāng)中是不能超過12位元組)程式碼是獨(dú)立在setUsername()方法之外的。從驗(yàn)證到儲(chǔ)存到資料庫的過程輕而易舉。而且,這是一個(gè)非常好的單憑經(jīng)驗(yàn)的方法,一個(gè)方法或一個(gè)類別需要做的越少,它的重複使用的機(jī)會(huì)將會(huì)越大。這在你開始寫一個(gè)子類時(shí)更加明顯,假如你需要一個(gè)子類,並且又要跳過(忽略)父類方法(行為)中的一些特殊的細(xì)節(jié),如果(針對(duì)這個(gè)細(xì)節(jié)的)方法很小而又精細(xì),(修改它)只是一瞬間的過程,而如果這個(gè)方法非常臃腫,針對(duì)多種目的,你可能將在複製子類中大量代碼中鬱悶而終。
比方說,假如Admin是User類別的子類別。我們對(duì)adamin的用戶可能會(huì)有不同的,相對(duì)苛刻一些的密碼驗(yàn)證方法。最好是跨過父類別的驗(yàn)證方法和整個(gè)setUsername()方法(在子類別中重寫)。
更多關(guān)於存取器(Accessor)
以下是一些其他的例子來說明如何讓存取器用的更有效果。很多時(shí)候我們可能要計(jì)算結(jié)果,而不是簡單的回傳數(shù)組中的靜態(tài)資料。存取方法還能做的一個(gè)有用的事情就是更新(updating)快取中的值。當(dāng)所有的變動(dòng)(對(duì)資料的所有操作)都要通過setX()方法的時(shí)候,這正是我們根據(jù)X來重置快取中的值的時(shí)刻。 於是我們的這個(gè)類別層次變得更加明了:內(nèi)部變數(shù)$_data的處理被替換成受保護(hù)的私有方法(private methods)_getData()和_setData() 這類方法被轉(zhuǎn)移到被稱作記錄(Record)的抽象的超級(jí)類別(super class),當(dāng)然它是User類別下的子類別這個(gè)記錄類別(Record class)掌握所有存取陣列$ _data的細(xì)節(jié),在內(nèi)容被修改之前呼叫驗(yàn)證的方法,以及將變更的通知發(fā)給記錄(Records),就像發(fā)給中心物件儲(chǔ)存(ObjectStore)實(shí)例。
class User extends Record {
// --- 省略程式碼--- //
/**
* 不顯示使用者的實(shí)際密碼,僅顯示一些與密碼值相同 strlen 的星號(hào)。
*/
函數(shù)password() {
$passLength = strlen($this->_getData('password'));
return str_repeat('*', $passLength);
}
/* *
* 設(shè)定使用者密碼不受影響。
*/
function setPassword($newPassword) {
$this->_setData('password', $newPassword);
}
/**
* fullName 是從firstName 和lastName
* 派生的屬性,不需要儲(chǔ)存為變數(shù)。
* 因此它是唯讀的,並且沒有「setFullname()」存取器方法。
* /
function fullName() {
return $this->firstName() . 」 「。 $this->lastName();
}
/**
* 支出限額回傳用戶支出限額的金錢價(jià)值。
* 該值作為 INT 儲(chǔ)存在資料庫中,無需
* 更昂貴的 DECIMAL 或 DOUBLE 列類型。
*/
function SpendingLimit() {
return $this->_getData('spendingLimit') / 100 ;
}
/**
* set 存取器將貨幣值乘以 100,因此它可以再次作為 INT 值儲(chǔ)存在資料庫中
*。
*/
function setSpendingLimit($newSpendLimit) {
$this->_setData('spendingLimit', $newSpendLimit * 100); >}
/**
* validateSpendingLimit 不在此類中調(diào)用,而是由 Record 超類中的 _setData() 方法自動(dòng)調(diào)用
* ,而 Record 超類別又由 setSpendingLimit() 方法調(diào)用。
*/
function validateSpendingLimit(&$someLimit) {
if (is_numeric($someLimit) AND $someLimit >= 0) {
回真?? >回真;
} else {
throw new Exception("支出限額必須為非負(fù)整數(shù)"); //僅PHP5
}
}
}
/**
* Record 是所有資料庫物件的超類別。
*/
抽象類別Record {
var $_data = array();
var $_modifiedKeys = array(); // 追蹤自建立/取得記錄以來哪些欄位已變更
/**
* 傳回 $_data 關(guān)聯(lián)數(shù)組中的一個(gè)元素。
*/
function _getData($attributeName) {
return $this->_data[ $屬性名稱];
}
/**
* 如果提供的值通過驗(yàn)證,則此
* 設(shè)定 $_data 關(guān)聯(lián)數(shù)組中的值。
*/
function _setData($attributeName, $value) {
if ($this->validateAttribute($attributeName, $value)) {
if ($value != $this->_data[ $attributeName]) {
$this->_data[$attributeName] = $value;
$this->_modifiedKeys[] = $attributeName;
$this->didChange();
} else {
// 新值與目前值相同
// 不需要更改
}
}
}
/**
* 對(duì)於名為「foo」的屬性,它將尋找名為「validateFoo()」的方法
* 並呼叫它(如果存在)。否則傳回 true(表示驗(yàn)證通過)。
*/
function validateAttribute($attributeName, &$value) {
$methodName = 'validate' . $屬性名稱;
if (method_exists($this, $methodName)) {
return $this->$methodName( $value);
} else {
回傳true;
}
}
function didChange() {
//通知objectStore這條記錄發(fā)生了變化
}
}
?>
現(xiàn)在我們擁有了一個(gè)抽象的超級(jí)類別(Record),我們可以將User類別裡面大量的程式碼轉(zhuǎn)移出來,而讓這個(gè)User的子類別來關(guān)注User的特殊項(xiàng)目如存取和驗(yàn)證方法。您可能已經(jīng)注意到在我們的這個(gè)記錄類別(隱藏類別)中沒有任何 SQL 程式碼。這不是疏忽或遺漏!物件儲(chǔ)存類別(ObjectStore 類別)(在第二部分)將負(fù)責(zé)所有和資料庫的交互,以及我們的超級(jí)類別記錄的實(shí)例化。這樣使我們的記錄類別更加精簡有效率,而這對(duì)於評(píng)估我們處理大量物件的效率的時(shí)候是個(gè)重要因素。

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級(jí)程式碼編輯軟體(SublimeText3)

熱門話題

在HTML中合理使用語義化標(biāo)籤能提升頁面結(jié)構(gòu)清晰度、可訪問性和SEO效果。 1.用於獨(dú)立內(nèi)容區(qū)塊,如博客文章或評(píng)論,需保持自包含性;2.用於歸類相關(guān)內(nèi)容,通常包含標(biāo)題,適用於頁面不同模塊;3.用於與主內(nèi)容相關(guān)但非核心的輔助信息,如側(cè)邊欄推薦或作者簡介。實(shí)際開發(fā)中應(yīng)結(jié)合、等標(biāo)籤,避免過度嵌套,保持結(jié)構(gòu)簡潔,並通過開發(fā)者工具驗(yàn)證結(jié)構(gòu)合理性。

要重置MySQL的root密碼,請(qǐng)按以下步驟操作:1.停止MySQL服務(wù)器,使用sudosystemctlstopmysql或sudosystemctlstopmysqld;2.以--skip-grant-tables模式啟動(dòng)MySQL,執(zhí)行sudomysqld--skip-grant-tables&;3.登錄MySQL並根據(jù)版本執(zhí)行相應(yīng)的SQL命令修改密碼,如FLUSHPRIVILEGES;ALTERUSER'root'@'localhost'IDENTIFIEDBY'your_new

處理MySQL中的NULL值需注意:1.設(shè)計(jì)表時(shí)關(guān)鍵字段設(shè)為NOTNULL,可選字段允許NULL;2.查詢判斷必須用ISNULL或ISNOTNULL,不能用=或!=;3.可用IFNULL或COALESCE函數(shù)替換顯示默認(rèn)值;4.插入或更新時(shí)直接使用NULL值需謹(jǐn)慎,注意數(shù)據(jù)源和ORM框架處理方式。 NULL表示未知值,不等於任何值,包括自身,因此查詢、統(tǒng)計(jì)、連接表時(shí)要特別小心,避免漏數(shù)據(jù)或邏輯錯(cuò)誤。合理使用函數(shù)和約束可以有效減少因NULL帶來的干擾。

開啟MySQL慢查詢?nèi)罩静⒎治隹啥ㄎ恍阅軉栴}。1.編輯配置文件或動(dòng)態(tài)設(shè)置slow_query_log和long_query_time;2.日志包含Query_time、Lock_time、Rows_examined等關(guān)鍵字段,輔助判斷效率瓶頸;3.使用mysqldumpslow或pt-query-digest工具高效分析日志;4.優(yōu)化建議包括添加索引、避免SELECT*、拆分復(fù)雜查詢等。例如為user_id加索引能顯著減少掃描行數(shù),提升查詢效率。

mysqldump是用於執(zhí)行MySQL數(shù)據(jù)庫邏輯備份的常用工具,它生成包含CREATE和INSERT語句的SQL文件以重建數(shù)據(jù)庫。 1.它不備份原始文件,而是將數(shù)據(jù)庫結(jié)構(gòu)和內(nèi)容轉(zhuǎn)換為可移植的SQL命令;2.適用於小型數(shù)據(jù)庫或選擇性恢復(fù),不適合TB級(jí)數(shù)據(jù)快速恢復(fù);3.常用選項(xiàng)包括--single-transaction、--databases、--all-databases、--routines等;4.恢復(fù)時(shí)使用mysql命令導(dǎo)入,並可關(guān)閉外鍵檢查以提升速度;5.建議定期測(cè)試備份、使用壓縮、自動(dòng)化調(diào)

MySQL分頁常用LIMIT和OFFSET實(shí)現(xiàn),但大數(shù)據(jù)量下性能較差。 1.LIMIT控制每頁數(shù)量,OFFSET控制起始位置,語法為LIMITNOFFSETM;2.性能問題源於OFFSET掃描過多記錄並丟棄,導(dǎo)致效率低;3.優(yōu)化建議包括使用游標(biāo)分頁、索引加速、懶加載;4.游標(biāo)分頁通過上一頁最後一條記錄的唯一值定位下一頁起點(diǎn),避免OFFSET,適合“下一頁”操作,不適合隨機(jī)跳轉(zhuǎn)。

MySQL事務(wù)和鎖機(jī)制是並發(fā)控制和性能調(diào)優(yōu)的關(guān)鍵。 1.使用事務(wù)時(shí),務(wù)必顯式開啟並保持事務(wù)短小,避免長事務(wù)導(dǎo)致資源佔(zhàn)用和undolog膨脹;2.加鎖操作包括共享鎖和排他鎖,SELECT...FORUPDATE加X鎖,SELECT...LOCKINSHAREMODE加S鎖,寫操作自動(dòng)加鎖,應(yīng)使用索引減少鎖粒度;3.隔離級(jí)別默認(rèn)為可重複讀,適用於大多數(shù)場(chǎng)景,修改需謹(jǐn)慎;4.死鎖排查可通過SHOWENGINEINNODBSTATUS命令分析最近一次死鎖詳情,優(yōu)化方式包括統(tǒng)一執(zhí)行順序、增加索引、引入隊(duì)列系

GROUPBY用於按字段分組數(shù)據(jù)並執(zhí)行聚合操作,HAVING用於過濾分組後的結(jié)果。例如,使用GROUPBYcustomer_id可計(jì)算每個(gè)客戶的總消費(fèi)金額;配合HAVING可篩選出總消費(fèi)超過1000的客戶。 SELECT後的非聚合字段必須出現(xiàn)在GROUPBY中,HAVING可使用別名或原始表達(dá)式進(jìn)行條件篩選。常見技巧包括統(tǒng)計(jì)每組數(shù)量、多字段分組、結(jié)合多個(gè)條件過濾。
