1
回答
PHP防止一次请求多次调用同一函数或方法重复查询数据库的方法
注册华为云得mate10,2.9折抢先购!>>>   

在PHP开发中,为了实现需求或者因为代码质量,难免会出现在一次请求中多次调用同一函数或类方法。如果在这一函数或者类方法中需要查询数据库,多次调用时就会多次查询数据库。如果这多次查询结果还是一样的,就会造成服务器资源浪费,节约这部分被浪费的资源,在并发量大或者服务器配置低的情况下就很有用。

例如,在开发用户相关模块时定义了一个获取用户信息的函数:

function GetUserInfo($id) { /* 此处省略数据库相关初始化 */ $user_info = $db->getRow($sql); if (!is_array($user_info)) {
		$user_info = array();
	} return $user_info;
}

在请求开始时是初始化文件中,先获取当前登录用户信息:

$current_user = GetUserInfo($_SESSION['user_id']); if (!$current_user) { /* ...... */ } else { /* ...... */ }

在实际处理文件中,可能再次或多次通过GetUserInfo函数获取当前登录用户信息,甚至在模板里面一次或多次通过GetUserInfo函数获取当前登录用户信息。

在这种情况下,用户信息基本上没有变动,也很少出现在一次请求中,开头和结尾的当前用户信息不一样的情况,那调用了GetUserInfo函数几次,就几次打开、查询、关闭数据库。再多定义几个这种类似的函数和多次调用,那就又多次打开、查询、关闭数据库。

如何避免这种情况呢?这就要用到static(静态变量)。

静态变量仅在局部函数域中存在且只被初始化一次,当程序执行离开此作用域时,其值不会消失,会使用上次执行的结果。一般的函数内变量在函数结束后会释放,比如局部变量,但是静态变量却不会。也就是说,下次再调用这个函数的时候,该变量的值会保留下来。

那我们将GetUserInfo函数改一下:

function GetUserInfo($id) { static $users = array(); if (isset($users[$id])) { return $users[$id];
	} /* 此处省略数据库相关初始化 */ $user_info = $db->getRow($sql); if (!is_array($user_info)) {
		$user_info = array();
	}
	$users[$id] = $user_info; return $user_info;
}

这样的话,在一次请求当中,获取过的用户信息都会保留在内存中,直到本次请求完成或关闭。即使多次调用GetUserInfo函数获取同一用户信息,就会先判断是否已经查询过这个用户,如果已经查询过一次,就直接返回上次查询出来的信息。

上面举的例子看起来有点像面向过程的写法,实际上,面向对象的写法也是差不多的。

比如,定义了这么几个类:

class AClass { public function __construct() {
		$user = $this->GetUserInfo($_SESSION['user_id']); /* 接下来做了用户数据处理 */ } protected function GetUserInfo($id) { /* 此处省略数据库相关初始化 */ $user_info = $db->getRow($sql); if (!$user_info) {
			$user_info = array();
		} return $user_info;
	}
	
} class BClass extends AClass { public function __construct() { parent::__construct();
		$user = $this->GetUserInfo($_SESSION['user_id']); /* 接下来因为需求原因,重新做用户数据处理 */ }
	
} class CClass extends BClass { public function __construct() { parent::__construct();
		$user = $this->GetUserInfo($_SESSION['id']); /* 接下来因为使用场景,又要重新做用户数据处理 */ } public function index() {
		$user = $this->GetUserInfo($_SESSION['id']); /* 接下来又做了一次用户数据处理,在模板里面使用 */ $this->display('index.html');
	}
	
}

同样的,我们将AClass中的GetUserInfo方法改一下:

class AClass { public function __construct() {
		$user = $this->GetUserInfo($_SESSION['user_id']); /* 接下来做了用户数据处理 */ } protected function GetUserInfo($id) { static $users = array(); if (isset($users[$id])) { return $users[$id];
		} /* 此处省略数据库相关初始化 */ $user_info = $db->getRow($sql); if (!$user_info) {
			$user_info = array();
		}
		$users[$id] = $user_info; return $user_info;
	}
	
}

也同样解决了重复查询数据库的问题。

各位看官不要觉得这样写很搞笑,在实际开发中是会出现这种情况的,尤其是对于新手来说。本着学习的态度,大家相互讨论,共同进步,欢迎吐槽。

直接从我的博文copy过来的,部分格式可能错乱,可去我博客看原文。

<无标签>
举报
零度开水
发帖于1年前 1回/1K+阅
顶部