函數prepare
為使用例1中的模板,你要做的第一件事是建立好prepare()函數,為確保無帶引號的字元被偶然解析為佔位符,函數應該移除query內所有字串,並把它們暫時儲存在一個陣列內。而字串本身也會被佔位符取代,其通常被辨識為不應該在SQL語句中出現的字串序列。在query的編譯期間,過程佔位符會先被替換,接著把字串放回query中,這是透過preg_replace()函數,和另一個用作preg_replace()函數的helper回呼函數完成的。
例2:prepare()函數
/** * 把query准备为一个存储过程。 * @param string $query Prepared query text * @return void */ public function prepare($query) { $this->stored_procedure = true; $this->quote_store = array(); //清除引号 $this->query = preg_replace(self::$QUOTE_MATCH, '$this->sql_quote_replace("1"?"1":'2')', $query); } private function sql_quote_replace($match) { $number = count($this->query_strings); $this->query_strings[] = $match; return "$||$$number"; }
在此留意對靜態QUOTE_MATCH屬性private的使用,還有quote_store屬性和sql_quote_replace()函數。相較於protected,在此定義為private更能確保任何重載query類別prepare()方法的子類別使用其自身的機制來剔除引號。
函數compile
下一步是建立compile()與execute()函數。
函數compile()如例3所示,功能如下:
·接受的參數數目可變(即可變參數),其將匹配query中的佔位符。
·檢查佔位符是否為正確的資料類型,並把它替換為參數中的值。
·把query當作字串傳回,但不執行它。
·如果query物件沒有使用prepare()函數初始化為一個預存過程,將會拋出一個例外。
例3:compile()函數
/** * 返回编译的query,但并不执行它。 * @param mixed $args,... Query Parameters * @return string Compiled Query */ public function compile($params) { if (! $this->stored_procedure) { throw new Exception("存储过程未被初始化!"); } /* 替代参数 */ $params = func_get_args(); // 取得函数参数 $query = preg_replace("/(?query); return $this->add_strings($query); //把字符串放回query中 } /** * 重新插入被prepare()函数移除的字符串。 */ private function add_strings($string) { $numbers = array_keys($this->query_strings); $count = count($numbers); $searches = array(); for($x = 0; $x < $count; $x++) { $searches[$x] = "$||${$numbers[$x]}"; } return str_replace($searches, $this->query_strings, $string); } /** * 每次执行,存储过程中都有一个占位符被替换。 */ protected function compile_callback($params, $index, $type) { --$index; /* 抛出一个异常 */ if (! isset($params[$index])) { throw new Exception("存储过程未收到所需的参数数目!"); } /* 可以在此添加别的类型,如日期和时间。 */ switch ($type) { case 'S': return '"' . $this->db->escape_string($params[$index]) . '"'; break; case 'I': return (int) $params[$index]; break; case 'N': return (float) $params[$index]; default: throw new Exception("存储过程中指定的数据类型 '$type' 无法识别。"); } }
函數compile()中使用了兩個額外的函數,其中compile_callback()函數是作為在preg_replace()函數呼叫中的回呼函數,每一次在query中查找到佔位符,並將它替換為傳給compile函數的值時,都會執行它。
以上就是利用PHP的OOP特性實現資料保護(2)的內容,更多相關內容請關注PHP中文網(www.php.cn)!