萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> php編程 >> 利用PHP的OOP特性實現數據保護

利用PHP的OOP特性實現數據保護

  在PHP 4中,聲明變量通常使用var,而在PHP 5中,可使用面向對象編程(OOP)的特性來自定義數據的可見性--即可訪問性,可見性在此與變量作用域非常類似,但提供了更好的控制機制,有以下三種類型的可見性修飾符:

Public(默認)--變量可在全局范圍內訪問或修改。
Protected--變量只能在類本身及直接派生(使用extends語句)類內訪問或修改。
Private--變量只能在類內部訪問或修改。

與接口實現類似,在程序中違反這些規則將會導致嚴重的錯誤;且與接口類似的是,它們的存在純粹是為了方便程序員。但這並不意味著可以忽略它們,指定某個類成員變量的可見性,可保護對象內的數據免受外界影響。

假設有一個MySqlDB類,一個$link變量在其中聲明為private,這意味著這個變量只能從對象內部使用$this變量訪問,這防止了類外其他對象或函數的意外覆蓋,在此,我們將使用可見性特性幫助我們創建一個query對象。

你可以把query當作一個單獨的實體,它可以執行,並且返回結果。一些數據庫系統也具有存儲過程,存儲過程與函數很相似,它們存儲查詢語句,並在調用時接受相應的參數,但MySQL在5.1版本之前並沒有提供類似功能,某些其他類型的數據庫管理系統也沒有。

在本文中,將把上述兩個特性結合進示例的query對象中,示例將模擬一個基本的存儲過程,並在內部保存結果指針。目前,重點是從對象中執行query,在此可以調用MySqlDB對象的query()函數。

可在query對象中定義如下的public函數:

__construct()--構造函數接受一個包含了實現DB接口對象實例引用的參數。

prepare()--函數prepare()初始化query的存儲過程。它可能包含一個或多個有限的占位符,而其將會作為參數傳遞給execute()函數。占位符定義為與參數個數有關的一個冒號緊跟一個整數及與參數類型有關的一個字母。

包含占位符的一個簡單的query看起來像以下這樣:
 

SELECT col1,col2 FROM table_name WHERE col1=:1I

  execute()--函數execute()將執行query。如果它被prepare()函數過早地初始化為一個存儲過程,任何傳遞進來的參數都會被作為存儲過程的執行參數,否則,第一個參數只會被作為查詢文本。函數execute()將返回執行查詢後的結果。



  compile()--函數compile()與函數execute()類似,實際上,query並沒有執行,而是替換查詢字符串中所有占位符,接受存儲過程的參數,並返回query的編譯版本。



  

受保護的成員

   正如上面所提到的,可見性的概念可用於隱藏對象的內部工作,保護內部工作所需的數據完整性。前面已經解釋,query返回的結果指針將會保存為 protected屬性,在此使用保護成員是因為從query對象派生出來的特定數據庫query對象可能會重載某些核心功能。



  

深掘代碼

  理論說夠了,現在開始編寫代碼,首先,創建一個例1所示的模板:



  例1:數據庫query類的一個模板



class DBQuery
{
/**
*保存一個實現了DB接口對象的引用。
*/
protected $db;

/**
*如果是一個存儲過程,設為true。
*/
protected $stored_procedure = false;

/**
*保存一個刪除了所有字符串的query。
*/
private $query;

/**
*用於在SQL中匹配引號。
*/
private static $QUOTE_MATCH = "/(".*(?db = $db;
}

public function prepare($query)
{
$this->stored_procedure = true;
}

public function compile($args)
{}

public function execute($query)
{}
}

  

函數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) {
copyright © 萬盛學電腦網 all rights reserved