在做完必要的檢查、整理和基本測試後,如果還有時間,可以針對程式運行做整合測試,基本上就是針對PHP+MySQL的運作做整合性的測試,避免發生資料庫連不上或是編碼設錯,時區沒設定等狀況
撰寫共用函式檔
共用函式的目的在於簡化CRUD的動作,同時減少撰寫SQL語法時的錯誤,最後則是為了讓除錯過程可以變得簡單一些。
這邊我們建議採用物件導向的方式來簡化自訂函式的撰寫,但是考量到檢定時間的限制,所以並不是全面的採用物件導向,只是把常用的自訂函式包裝成一個工具類別(Class)來使用而已,
宣告類別
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
| class DB{
protected $dsn='mysql:host=localhost;charset=utf8;dbname=db13'; protected $table; protected $pdo; protected $links;
function __construct($table) { $this->table=$table;
$this->pdo=new PDO($this->dsn,'root',''); } }
|
撰寫內部共用方法
由於CRUD的SQL語法中有許多是類似的,比如where 後的句型;而我們希望能透過一些設計方式讓我們在建立SQL語法時可以更簡便,因此我們將一些接近的用法獨立出來做成一個可以被呼叫引用的方法,藉此來降低程式碼的重覆,提高可讀性、維護及擴充。
a2s()-內部保護函式,用來簡化陣列參數的字串轉換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
protected function a2s($array){ foreach($array as $key => $value){
if($key!='id'){ $tmp[]="`$key`='$value'"; } } return $tmp; }
|
sql_id()-用來組合有含id的陣列資料為sql語句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
protected function sql_one($sql,$arg){ if(is_array($arg)){ $tmp=$this->a2s($arg); $sql=$sql." where ". join(" && ",$tmp); }else{ $sql=$sql. " where `id`='$arg'"; } return $sql; }
|
sql_all()-用來組合有特定條件並且為多筆結果的sql語句
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
|
protected function sql_all($sql,...$arg){ if(!empty($arg)){
if(isset($arg[0])){
if(is_array($arg[0])){ $tmp=$this->a2s($arg[0]); $sql=$sql . " where ".join(" && ",$tmp); }else{ $sql=$sql .$arg[0]; } }
if(isset($arg[1])){ $sql=$sql. $arg[1]; } } return $sql; }
|
math()-內部函式,用來做為聚合函式的sql語法轉換
雖然也可以直接使用,但是直接使用的話需要輸入較多的參數,所以我們利用類別內可以互相呼的方式來簡化參數的使用,對外則是以max(‘欄位’,’條件’)來使用,而不是較多參數的math(‘max’,’欄位’,’條件’)。
1 2 3 4 5 6 7
| protected function math($math,$col,...$arg){ $sql="select $math($col) from $this->table "; $sql=$this->sql_all($sql,...$arg);
return $this->pdo->query($sql)->fetchColumn(); }
|
撰寫外部公開方法(資料庫相關功能)
外部公開方法是在類別實例化成物件後,提供外部來呼叫用的,可以根據自己的專案需要來加上各式便利的功能
$table->all()-查詢符合條件的全部資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
function all(...$arg){ $sql="select * from $this->table ";
$sql=$this->sql_all($sql,...$arg);
return $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC); }
|
$table->find($id)-查詢符合條件的單筆資料
1 2 3 4 5 6 7 8 9 10
| function find($arg){ $sql="select * from $this->table ";
$sql=$this->sql_id($sql,$arg);
return $this->pdo->query($sql)->fetch(PDO::FETCH_ASSOC); }
|
$table->del($id)-刪除資料
1 2 3 4 5 6 7 8 9 10
| function del($arg){ $sql="delete from $this->table ";
$sql=$this->sql_id($sql,$arg);
return $this->pdo->exec($sql); }
|
$table->save($array)-新增/更新資料
利用新增和更新語法的特點整合兩個動作為一個,簡化函式的數量並提高函式的通用性;
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
|
function save($arg){ if(isset($arg['id'])){ $sql="update $this->table set ";
$tmp=$this->a2s($arg);
$sql=$sql . join(",",$tmp);
$sql=$sql . " where `id`='{$arg['id']}'"; }else{ $key=array_keys($arg);
$sql="insert into $this->table (`".join("`,`",$key)."`) value('".join("','",$arg)."')"; }
return $this->pdo->exec($sql); }
|
sum()/max()/min()…-使用聚合函式來計算某個欄位的結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
function max($col,...$arg){ return $this->math('max',$col,...$arg); }
function min($col,...$arg){ return $this->math('min',$col,...$arg); }
function sum($col,...$arg){ return $this->math('sum',$col,...$arg); }
|
撰寫外部公開方法(畫面相關功能)
由於乙級的題目中有不少的功能是需要把資料呈現在畫面上,為了簡化頁面的程式撰寫,所以我們把這一類的功能抽像出來放到類別中。
view($url,$arg=[])-引入頁面模版
1 2 3 4 5 6 7 8 9 10 11 12
|
function view($path,$arg=[]){ extract($arg);
include($path); }
|
paginate($num,$arg=null)-根據分頁的資料筆數來回傳一頁中的資料
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
|
function paginate($num,$arg=null){ $total=$this->count($arg); $pages=ceil($total/$num); $now=$_GET['p']??1; $start=($now-1)*$num;
$rows=$this->all($arg," limit $start,$num");
$this->links=[ 'total'=>$total, 'pages'=>$pages, 'now'=>$now, 'start'=>$start, 'table'=>$this->table ];
return $rows; }
|
links()-根據分頁方法的資料,回傳分頁連結的html程式碼
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
|
function links(){ $html='';
if($this->links['now']-1>=1){ $prev=$this->links['now']-1; $html.="<a href='?do=$this->table&p=$prev'> < </a>"; }
for($i=1;$i<=$this->links['pages'];$i++){
$size=($this->links['now']==$i)?'24px':'18px'; $html.="<a href='?do=$this->table&p=$i' style='font-size:$size'> $i </a>"; }
if($this->links['now']+1<=$this->links['pages']){ $next=$this->links['now']+1; $html.="<a href='?do=$this->table&p=$next'> > </a>"; }
return $html; }
|
撰寫輔助用的全域函式
有些功能不必然都要放到類別中,我們可以宣告在共用的引入檔中,做為全域隨時可以呼叫的工具函式
q($sql)-複雜SQL語法的簡化函式
1 2 3 4 5 6
| public function q($sql){ $dsn="mysql:host=localhost;charset=utf8;dbname=db01"; $pdo=new PDO($dsn,'root',''); return $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC); }
|
也可以在DB class中建一個q()函式來使用
DB.php
1 2 3 4 5 6 7
| class DB{ .....
function q($sql){ return $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC); } }
|
$to($url)-頁面導向輔助函式
此函式會獨立在 DB
這個類別外,但是會和共用檔放在一起,然後include到所有的頁面去使用,主要目的是簡化header指令的語法,避免拚字錯誤之類的事發生。
1 2 3
| function to($url){ header("location:".$url); }
|
dd()-PHP陣列查看
1 2 3 4 5 6
| function dd($array){ echo "<pre>"; print_r($array); echo "</pre>"; }
|
時區設定
有些題組會使用到時間,直接修改apache設定檔或php.ini都可以,但如果是一般坊間的server,可能沒有提供使用者去更改全域設定的功能,此時可以簡單的加上一個動態時區設定的語法,讓我們的程式在執行期間可以使用我們自行設定的時區:
1
| date_default_timezone_set("Asia/Taipei");
|
啟用session
有很多功能需要透過session來暫存狀態,因此我們可以在共用檔中先啟月session,方便在各個頁面都可以操作session。
預宣告資料表變數
由於共用函式檔會include到所有的頁面去使用,如果每次要使用時才去做 new DB('table')
會有點囉嗦,因此可以考慮把常用或會用到的資料表都先建立一個 DB
的實體出來,當成全域變數先宣告,之後在各個頁面就可以直接套用。
1 2 3 4
| $User=new DB('user'); $Menu=new DB('menu');
|
也可以使用繼承的方式來建立一個特定的資料表類別,並預先建立相關的成員或函式,如此也可以簡化宣告物件和後續的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| include_once "DB.php";
class User extends DB{
function __construct() { parent::__construct('user'); } }
class Menu extends DB{
function __construct() { parent::__construct('menu'); } }
$User=new User; $Menu=new Menu;
|
測試CRUD正常運作
- 建一個資料表
- 寫一個簡單的SQl語法來測試CRUD都正常
測試前端JS及jQuery運作正常