下一期 如何寫一個(gè)屬于自己的數(shù)據(jù)庫(kù)封裝(2) - 數(shù)據(jù)庫(kù)連接
寫在前頭
- 依然在前進(jìn)的菜鳥一只,錯(cuò)誤什么的請(qǐng)輕噴指出
- 對(duì)于數(shù)據(jù)庫(kù)連接由于較淺的工作經(jīng)驗(yàn)所以無法完全覆蓋棚蓄,較復(fù)雜的query可能會(huì)有意想不到的bug
- 所以本系列只提供思路败砂,成熟穩(wěn)定的數(shù)據(jù)庫(kù)封裝有請(qǐng)自行搜索
- 編寫該系列的初衷就是為了拋磚引玉昧诱, 在每一節(jié)的后端拥刻,我都會(huì)提出一些個(gè)人疑問(或無)抹竹,希望能引出大神為我解答迷惑
- 使用的php版本為7.0+线罕,該系列并不向下兼容,還在5.6版本的童鞋們快過來玩呀
- 數(shù)據(jù)庫(kù)封裝參考了laravel的源代碼柒莉, 如有雷同闻坚, 不是巧合
最終效果
假設(shè)我們有一個(gè)表,名'Actor', 經(jīng)過簡(jiǎn)單設(shè)置, 可以直接如下調(diào)用
$a = Actor::select('first_name', 'last_name')
->where('first_name', 'NICK')
->where('last_name', 'WAHLBERG')
->first()
var_dump($a);
返回格式
object(Actor)[11]
public 'first_name' => string 'NICK' (length=4)
public 'last_name' => string 'WAHLBERG' (length=8)
返回的數(shù)據(jù)依然可操作(update/delete)
$a->update(...);
$a->delete();
更多例子可以查看第4期 - 如何寫一個(gè)屬于自己的數(shù)據(jù)庫(kù)封裝(4) - 查詢 - 入門篇用法
本期知識(shí)點(diǎn)
常見的數(shù)據(jù)庫(kù)連接寫法
對(duì)php有一定了解的人都知道,相比已被淘汰的mysql或取而代之的mysqli兢孝, pdo 可以避免SQL注入式攻擊窿凤, 更安全, 而且面向?qū)ο螅?所以請(qǐng)看下方pdo例子
<?php
$driver='mysql'; //數(shù)據(jù)庫(kù)類型
$host='localhost'; //數(shù)據(jù)庫(kù)主機(jī)名
$db = 'sakila'; //數(shù)據(jù)庫(kù)名稱
$username='root'; //數(shù)據(jù)庫(kù)連接用戶名
$password=''; //數(shù)據(jù)庫(kù)密碼
$dsn="$driver:host=$host;dbname=$db";
try {
$pdo= new PDO($dsn, $username, $password); //初始化一個(gè)PDO對(duì)象
$sql = "select * from actor";
$res = $pdo->query($sql); // 從actor中獲取所有數(shù)據(jù)
foreach($res as $row)
echo $row['first_name']."<br>";
} catch (PDOException $e) {
die($e->getMessage());
}
例子中的代碼看起來非常簡(jiǎn)潔, 然而, 這么做真的好嗎?
很多菜鳥因?yàn)榻?jīng)驗(yàn)或自身的原因, 在實(shí)現(xiàn)業(yè)務(wù)邏輯時(shí)并未考慮過維護(hù)代碼, 要不重復(fù)性代碼全寫在一塊, 要不隨便寫個(gè)函數(shù)概括進(jìn)去, 這一類代碼, 是導(dǎo)致經(jīng)手人辭職的最大元兇
代碼太爛了我看不下去
因此, 考慮到一個(gè)項(xiàng)目長(zhǎng)遠(yuǎn)開發(fā), 我們需要一個(gè)封裝類來減少代碼的重復(fù)性跨蟹, 就像平時(shí)自行寫的一些輔助函數(shù)雳殊, 不過封裝類略微進(jìn)階而已。
基本思路
那么窗轩,應(yīng)該怎么寫呢夯秃?
平時(shí)我們要簡(jiǎn)略一些代碼, 都會(huì)自行編寫一些輔助函數(shù)痢艺,比如我個(gè)人有個(gè)不好的習(xí)慣仓洼,不喜歡用編輯器的調(diào)試功能(畫外音:我用的是sublime text 3),那么debug的時(shí)候一開始都是這么寫的
$a = "is bug";
die(var_dump($a)); // 輸出變量并且停止運(yùn)行之后的代碼
/***從xdebug得知bug出現(xiàn)在這一行堤舒,所以查看上一行的邏輯與數(shù)據(jù) ***/
die(var_dump())的出場(chǎng)率略高色建, 因此我將它們寫成了一個(gè)輔助函數(shù)
function dd($var) {
die(var_dump($var));
}
同樣道理,在數(shù)據(jù)庫(kù)讀取的時(shí)候舌缤,select的出場(chǎng)率極高箕戳, 所以簡(jiǎn)單的包裹一下
function select($pdo, $table, $require, $where = []) {
$w = [];
// 將搜索條件轉(zhuǎn)化為數(shù)據(jù)庫(kù)命令能接受的格式
foreach ($where as $key => &$val)
$w[] = "$key = '$val'";
// 有時(shí)候并不需要條件某残,僅僅將所有數(shù)據(jù)取出,因此$where默認(rèn)為空
if(!empty($w))
$w = "where ".implode(', ', $w);
else
$w = "";
// 生成sql query
$sql = "select $require from $table $w";
// 將已生成的query帶入pdo實(shí)例
$res = $pdo->query($sql);
// 返回結(jié)果
return $res->fetchAll();
}
例子
select($pdo, 'actor', '*', ['first_name'=>'PENELOPE'])
/**
* 生成sql query => select * from actor where first_name = 'PENELOPE'
**/
總結(jié)一下陵吸, 數(shù)據(jù)庫(kù)封裝淺顯的形容就是將參數(shù)帶入輔助函數(shù)玻墅,讓其自動(dòng)生成SQL命令。
數(shù)據(jù)庫(kù)封裝的架構(gòu)
主要分成四個(gè)文件
- Connector.php - 負(fù)責(zé)與數(shù)據(jù)庫(kù)的通信壮虫, 請(qǐng)求與返回?cái)?shù)據(jù)庫(kù)數(shù)據(jù)
- Model.php - 入口文件澳厢,作為一個(gè)模型, 定義表的各種屬性(如主鍵, 表名等等), 并接受請(qǐng)求旨指, 返回?cái)?shù)據(jù)庫(kù)數(shù)據(jù)
- Grammar.php - 將Builder存儲(chǔ)的請(qǐng)求轉(zhuǎn)化為SQL語(yǔ)句
- Builder.php - 核心文件赏酥, 存儲(chǔ)Model的請(qǐng)求,調(diào)用Grammar編譯SQL語(yǔ)句谆构, 與參數(shù)變量一并送往Connector以獲取數(shù)據(jù)庫(kù)數(shù)據(jù)裸扶,再返還給Model
架構(gòu)可能解釋得不太好,但沒關(guān)系搬素, 接下來會(huì)慢慢一個(gè)個(gè)的深入解釋
大致如此呵晨, 如果可以的話點(diǎn)個(gè)贊,或在下方評(píng)論區(qū)討論熬尺, 只有反饋才能推動(dòng)一個(gè)懶癌晚期病患繼續(xù)前行摸屠。
下一期 如何寫一個(gè)屬于自己的數(shù)據(jù)庫(kù)封裝(2) - 數(shù)據(jù)庫(kù)連接