PHP头条
热点:



  

受保护的成员

   正如上面所提到的,可见性的概念可用于隐藏对象的内部工作,保护内部工作所需的数据完整性。前面已经解释,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) {
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函数的值时,都会执行它。  

函数execute

  最后,还需要构建函数execute(),函数execute()编译query并且使用DB 对象执行它,而DB对象在此是用于初始化DBQuery对象的。请注意在例4中,是怎样运用函数call_user_func_array()来得到编译 后的query的,而这样做的原因是,函数execute()要直到运行时,才能确定传递给它的参数数目。



  例4:execute()函数



/**
*
* 执行当前query,并把占位符替换为所提供的参数。
*
* @param mixed $queryParams,... Query parameter
* @return resource A reference to the resource representing the executed query.
*/
public function execute($queryParams = '')
{
//例如:SELECT * FROM table WHERE name=:1S AND type=:2I AND level=:3N
$args = func_get_args();

if ($this->stored_procedure) {
/* 调用函数compile以取得query */
$query = call_user_func_array(array($this, 'compile'), $args);
} else {
/* 如果存储过程未被初始化,就把它作为标准query执行。*/
$query = $queryParams;
}

$this->result = $this->db->query($query);

return $this->result;
}

  

全部整合起来

  为演示怎样使用query对象,下面构造了一个小例子,其将把DBQuery对象作为存储过程使用,并检查是否输入了正确的用户名与密码,请看例5:



  例5:



require 'mysql_db.php5';
require_once 'query2.php5';


$db = new MySqlDb;
$db->connect('host', 'username', 'pass');
$db->query('use content_management_system');

$query = new DBQuery($db);

$query->prepare('SELECT fname,sname FROM users WHERE username=:1S AND pword=:2S AND expire_time<:3I');

if ($result = $query->execute("visualad", "apron", time())) {
if ($db->num_rows($result) == 1) {
echo('凭证正确。');
} else {
echo('凭证不正确,会话已过期。');
}
} else {
echo('执行query时发生错误:' . $db->error());
}

  在本文中,你已看到了如何在声明类变量时,利用访问修饰符private、protected和public,保护数据和限制数据对象的可见性,同时,在PHP 5中,这些概念也可用于其他的数据类,保护其重要的内部数据。

www.phpzy.comtrue/php/3613.htmlTechArticle受保护的成员 正如上面所提到的,可见性的概念可用于隐藏对象的内部工作,保护内部工作所需的数据完整性。前面已经解释,query返回的结果指针将会保...

相关文章

相关频道:

PHP之友评论

今天推荐