前面我們已經完成了orm最核心部分–拼湊字串,接下來我們需要執行拼湊完成的sql語句。這裡只完成了insert操作
折騰(二)-與pdo進行組合,實現執行拼湊完成的sql語句
我們先建立兩張表 user
| 名 |
類型 |
長度 |
小數點 |
允許空值 |
| user_id |
int |
11 |
0 |
false |
| user_name |
varchar |
20 |
0 |
false |
| user_pwd |
varchar |
32 |
0 |
false |
order
| 名 |
類型 |
長度 |
小數點 |
允許空值 |
| order_id |
int |
11 |
0 |
false |
| user_id |
int |
11 |
0 |
false |
| order_price |
decimal |
5 |
2 |
false |
執行insert後的效果
與pdo組合之後的代碼如下,所示,有興趣可以研究下:
<?phpini_set('display_errors',1);ini_set('error_reporting',E_ALL);$map=function ($items) { if (!is_array($items)) { return $items; } else { $result=""; foreach ($items[1] as $item) { if ($result!="") $result.=","; $result.=$item.$this->_aliastb($item);//類似news,news_class 添加到form後面 } return $items[0].$result; }};class orm{ public $sql=array( "select"=>"select ", "from"=>array("from ",array()), "where"=>" where ", "orderby"=>" order by ", "insertinto"=>"insert into ",//insert操作 "insertfields"=>"", "values"=>" values" ); public $errorCode="";//錯誤碼 public $sql_bak=[]; public function __construct() { $this->sql_bak=$this->sql; $this->db=new PDO("mysql:host=127.0.0.1;dbname=testOrm","root","hello2016");//初始化資料庫連接 } public function select() { $fields=func_get_args(); foreach ($fields as $field) { if (is_array($field)) { $get_key=key($field);//擷取數組的key,其實就是表的名字,還需要在欄位前面加上表首碼 $this->__add(__FUNCTION__, $this->_aliastb($get_key).'.'.$field[$get_key]); } else { $this->__add(__FUNCTION__, $field); } } return $this; } //插入資料 public function insert() { $params=func_get_args();//擷取可變參數 $fields=[]; $fields_values=[]; $callback=[]; foreach ($params as $param) { if (is_array($param)) {//代表要拼接的是欄位和值 foreach ($param as $item) { //取出欄位名 $field=key($item); //取出欄位的值 $field_value=$item[$field]; //把上面的欄位和欄位值插入相對應的數組 $fields[]=$field; //拼湊字串的時候,判斷是否是字串,如果是字串則要加上單引號 if (is_string($field_value)) { $field_value="'".$field_value."'"; } $fields_values[]=$field_value; } //處理完參數之後,構造要插入欄位的拼湊 $this->__add("insertfields", '('.implode($fields,',').')'); $this->__add("values", '('.implode($fields_values,',').')'); } //如果是字串說明傳的是表名 if (is_string($param)) { $this->__add("insertinto", $param); } if(is_bool($param) && $param) //如果傳過來的參數是 布爾型,且為true,則預設開啟事務 { $this->db->beginTransaction(); } if (is_callable($param)) { $callback[]=$param; } } if(count($callback)>0) { $this->exec();//如果有匿名函數,則先執行SQL $this->clearConfig(); //恢複配置到最開始狀態,防止執行其他SQL時產生衝突。大家可以把SQL儲存到 某個類屬性中 foreach($callback as $call)//最後統一執行各個回呼函數 { $call=Closure::bind($call,$this);//這樣在匿名函數中就可以使用$this ,且這個$this就是orm對象 $call();//手工調用 匿名函數,這就是回調 } } return $this; } //避免sql語句相互幹擾 function clearConfig()//恢複到原有配置 { $this->sql=$this->sql_bak; } //排序 function orderby($str, $order) { $order=' '.$order; if (is_array($str)) { $tb=key($str); $this->__add(__FUNCTION__, $this->_aliastb($tb).'.'.$str[$tb].$order); } else { $this->__add(__FUNCTION__, $str.$order); } return $this; } //給表加別名 public function _aliastb($tbName) { return ' _'.$tbName; } public function from($tableName)//處理from過程 { if (is_array($tableName)) {//是數組的話就是代表多張表關聯 if (count($tableName)!=2) return $this;//參數值類似[["name"=>classid""],["name_class"]=>"id"],小於2滅有意義 $tb1=current($tableName); $tb2=next($tableName); //第一步,把表的key值作為from參數進行處理 $tb1_key=key($tb1); $tb1_value=$tb1[$tb1_key]; $tb2_key=key($tb2); $tb2_value=$tb2[$tb2_key]; $this->__add(__FUNCTION__, $tb1_key); $this->__add(__FUNCTION__, $tb2_key); //第二步,拼湊where條件 $whereString=' _'.$tb1_key.'.'.$tb1_value.'='."_".$tb2_key.'.'.$tb2_value; $this->where($whereString); return $this; } else { //字串則表示單張表查詢 $this->__add(__FUNCTION__, $tableName); return $this; } } public function where($str) { $this->__add(__FUNCTION__, $str, " and "); return $this; } public function __add($key, $str, $spliter=",")//實現字串的累加 { //調用不存在的方法,直接返回 if(!array_key_exists($key, $this->sql)) return ; if (is_array($this->sql[$key])) { //如果已經存在該項表明我們不做什麼處理 if (!in_array($str, $this->sql[$key][1])) { $this->sql[$key][1][]=$str; } } else { //如果是字串,直接進行字串累加// if (trim($this->sql[$key])!=$key) if (preg_replace('/\s/', '', $this->sql[$key])!=$key && preg_replace("/\s/", '', $this->sql[$key])!="") $this->sql[$key].=$spliter; $this->sql[$key].=$str; } } public function __toString() { global $map; $map=Closure::bind($map ,$this); // $filter=function ($value, $key) {// if(!is_string($value)) return true; if(is_array($value)) { if(count($value[1])>0) return true; return false; } //如果是Null 字元串也不參與累加 if(preg_replace("/\s/", '', $value)==$key || preg_replace("/\s/", "", $value )=="") return false; return true; }; $this->sql=array_filter($this->sql, $filter, ARRAY_FILTER_USE_BOTH ); $res=array_map($map, array_values($this->sql));// $this->sql=$this->sql_bak; return implode(array_values($res), ' ');//把新的數組重新構建成一個字串 } public function exec() { //測試執行方法 $sql=strval($this); //會自動調用 _tostring方法 $stmt=$this->db->prepare($sql); if(!$stmt->execute())//執行失敗, { if($this->db->inTransaction()) //判斷是否開啟了事務 { $this->db->rollBack();//執行復原 } $this->errorCode=$stmt->errorCode(); echo "執行Sql".$sql.'出錯,錯誤碼:'.$this->errorCode.",錯誤資訊:".$stmt->errorInfo()[2]; } return $this; } function getLastInsertID() //擷取上一條SQL執行情況 { return $this->db->lastInsertId(); } function getAll() //擷取全部取出的結果 { return $this->db->fetchAll(); } function commit() { //提交事務 if($this->db->inTransaction()) $this->db->commit(); }} $orm=new orm(); echo $orm->insert(true,[ ['user_name'=>"seven"], ['user_pwd'=>md5('123')] ],"user",function(){ $userid=$this->getLastInsertID(); //擷取使用者註冊後的自增ID $this->insert([ ['user_id'=>intval($userid)], ['order_price'=>100], ],"orders",function(){ if($this->errorCode=="") { $this->commit(); echo "sucess!"; } else { echo "fail!"; } }); });