「七天自制PHP框架」第二天:模型與數據庫
往期回顧:「七天自制PHP框架」第一天:路由與控制器,點擊此處
什麽是模型?
我們的WEB系統一定會和各種數據打交道,實際開發過程中,往往一個類對應了關系數據庫的一張或多張數據表,這裏就會出現兩個問題。
1.類和數據表,一方修改會導致另一方的修改,只要數據表結構不定下來,業務邏輯的開發幾乎沒法開工
2.獲取數據時會牽涉很多SQL語句的拼接,如果數據結構變動,這些SQL需要改寫
假如要開發一個博客系統,我們先設計兩個Model和兩張數據表
第一張數據表,表名是post,存儲了博客文章,數據如下:
第二章數據表,表名是comment,存儲了博客文章的評論,數據如下:
post和comment是一對多的關系,每一篇博客文章對應了多條評論,每一條評論只屬於一篇文章。
Model類的設計之前,我們先定義好三個接口
1 2 3 4 5 |
interface IModel{
public static function all();
public static function get( $id );
public static function where( $condition , $value );
}
|
定義Model類
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Model implements IModel{
public static $table ;
public static $db ;
public function __construct(){
self:: $db = new MySQL();
}
public static function get( $id ){
return self::where( ‘id‘ , $id );
}
public static function where( $condition , $value ){
$sql =sprintf( "select * from %s where %s=‘%s‘" ,self:: $table , $condition , $value );
return self:: $db ->Query( $sql );
}
public static function all(){
$sql =sprintf( "select * from %s" ,self:: $table );
return self:: $db ->Query( $sql );
}
}
|
這三個接口分別負責了三種查詢:遍歷查詢,條件查詢,按編號查詢,其實這三種接口的設計並不是最科學的,甚至get方法不過是where的一種特殊形式,但是這樣的設計並不影響我們工程,甚至也有助於理解,我們後期會對這段代碼做改動。
之所以在Model類裏就完成了SQL的拼接,就是希望在子類中不必重復再寫SQL。
然後是Post類的定義
1 2 3 4 5 6 7 |
class PostModel extends Model{
public $postid ;
public function __construct(){
parent::__construct();
parent:: $table = ‘post‘ ;
}
}
|
還有Comment類的定義
1 2 3 4 5 6 7 |
class CommentModel extends Model{
public $commentid ;
public function __construct(){
parent::__construct();
parent:: $table = ‘comment‘ ;
}
}
|
我們可以在控制器的方法中寫這樣的代碼來完成調用數據
1 2 3 4 5 6 7 8 |
$post = new PostModel();
$post ::all();
$arr = $post ::get( ‘1‘ );
var_dump( $arr );
$comment = new CommentModel();
$arr = $comment ::get( ‘2‘ );
var_dump( $arr );
|
我們發現,這樣的代碼很簡潔,但是問題也隨之而來,我們SQL查詢時候,還有很多復雜的聯表查詢如join操作,如此,拼接SQL還是不可避免的,這個復雜的問題,我們放在後面解決。
模型與數據庫
先寫一個DB抽象類,規定類需要實現的方法
1 2 3 4 5 6 7 8 9 10 11 |
abstract class DB{
private $IP ;
private $user ;
private $pwd ;
private $name ;
private $connection ;
abstract public function Execute( $sql );
abstract public function Query( $sql );
}
|
這裏以MySQL數據為例,當然你也完全可以實現一套Sqlite數據庫的接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
class MySQL extends DB{
public function MySQL(){
/*Config*/
$this ->IP= ‘*‘ ;
$this ->ServerID= ‘*‘ ;
$this ->ServerPassword= ‘*‘ ;
$this ->DataBaseName= ‘*‘ ;
/*End of Config*/
$this ->connection=mysqli_connect( $this ->IP, $this ->ServerID, $this ->ServerPassword, $this ->DataBaseName);
if (! $this ->connection){
die ( ‘Could not connect‘ . $this ->connection);
}
mysqli_query( $this ->connection, ‘set names utf8‘ );
}
public function Execute( $sql ){
return mysqli_query( $this ->connection, $sql );
}
public function Query( $sql ){
$result =mysqli_query( $this ->connection, $sql );
$arr = array ();
while ( $row =mysqli_fetch_array( $result )){
$arr []= $row ;
}
return $arr ;
}
public function Close(){
mysqli_close( $this ->connection);
}
}
|
談到數據庫類,上述的寫法仍不是最好的,因為我們可以使用單例模式來保證DB類只有一次初始化,來節省硬件資源的開銷,但這不是本節的主題,我們把設計模式放在之後來談。
「七天自制PHP框架」第二天:模型與數據庫