php - 在 PHP 方法中使用函数
问题描述
我有一个多年来一直在使用的 db 类。今天我注意到一件有趣的事。
function example_function($key)
{
global $db; // db variable - class
$a_id = 1; // example
$admins = $db->table('admins')->where('id','=',$a_id)->order('id','desc')->limit(1)->get();
$admin_data = $admins['data'][0];
$return = $admin_data[$key];
return $return;
}
$id = example_function('id');
$new = $db->table('rooms')->where('id','=',$id)->order('id','desc')->limit(2)->get();
print_r($new);
//WORKS
$new = $db->table('rooms')->where('id','=',2)->order('id','desc')->limit(2)->get();
print_r($new);
//WORKS
$new = $db->table('rooms')->where('id','=',example_function('id'))->order('id','desc')->limit(2)->get();
print_r($new);
//NOT WORKING ?
->where('id','=',example_function('id'))->
当我在这部分使用外部函数时,事情变得一团糟。
但以下也有效。在相关功能中对 db 进行另一项操作时,事情会变得一团糟。
function example_function($key)
{
return '1';
}
$new = $db->table('rooms')->where('id','=',example_function('id'))->order('id','desc')->limit(2)->get();
是全局使用的问题吗?还是数据库类错了?
数据库类
class DB
{
protected $connect;
protected $db_database = DB_DATABASE;
protected $db_host = DB_HOST;
protected $db_username = DB_USERNAME;
protected $db_password = DB_PASSWORD;
protected $db_name = DB_NAME;
protected $db_prefix = DB_PREFIX;
//parameters
protected $error = null;
protected $last_id = null;
protected $query = null;
protected $from = null;
protected $select = '*';
protected $where = null;
protected $group = null;
protected $order = null;
protected $limit = null;
protected $pagination_type = false;
protected $per_page = 0;
protected $get_arr = null;
function __construct()
{
try {
$this->connect = new PDO("{$this->db_database}:host={$this->db_host};dbname={$this->db_name};charset=utf8mb4", "{$this->db_username}", "{$this->db_password}");
$this->connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connect->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8mb4");
} catch ( PDOException $e ){
echo "<b>Veritabanı bağlantısı sağlanamadı! - Hata Kodu: </b>".$e->getMessage();
exit;
}
}
public function now($type="datetime")
{
switch($type)
{
case 'timestamp';
return time();
case 'date';
return date('-m-d');
case 'datetime';
return date('Y-m-d H:i:s');
default:
return date('Y-m-d H:i:s');
}
}
public function m_empty($data)
{
if($data=='' and $data!='0')
{
return true;
}
else
{
return false;
}
}
public function query($query,$arr=false)
{
$this->reset();
if($query!="")
{
try
{
$run = $this->connect->prepare($query);
if($arr)
{
if(is_array($arr))
{
$run->execute($arr);
return $run;
}
else
{
$run->execute(array($arr));
return $run;
}
}
else
{
$run->execute();
return $run;
}
} catch (PDOException $e) {
$this->error = $e->getMessage();
return false;
}
}
return false;
}
public function table($table)
{
$this->from = $this->db_prefix . $table;
return $this;
}
public function select($fields)
{
$this->select = $fields;
return $this;
}
public function where($field,$op='=',$values,$and="AND")
{
if(!$this->m_empty($field))
{
if(is_null($this->where))
{
$this->where="{$field} {$op} ?";
$this->get_arr[] = $values;
}
else
{
$this->where.=" {$and} {$field} {$op} ?";
$this->get_arr[] = $values;
}
}
return $this;
}
public function where_set($field,$op='=',$values,$and="AND")
{
if(!$this->m_empty($field) and !$this->m_empty($values))
{
if(is_null($this->where))
{
$this->where="{$field} {$op} {$values}";
}
else
{
$this->where.=" {$and} {$field} {$op} {$values}";
}
}
return $this;
}
public function group($fields)
{
if(is_null($this->group))
{
$this->group = $fields;
}
else
{
$this->group .=",{$fields}";
}
return $this;
}
public function order($field,$type="desc")
{
if(!is_null($field))
{
if(is_null($this->order))
{
if(strtolower($field)=="rand()")
{
$this->order = $field;
}
else
{
$this->order = $field.' '.strtoupper($type);
}
}
else
{
if(strtolower($field)=="rand()")
{
$this->order .=",{$fields}";
}
else
{
$this->order .= ','.$field.' '.strtoupper($type);
}
}
}
return $this;
}
public function limit($start,$end=null)
{
if(is_null($end))
{
if(is_numeric($start))
{
$this->limit = $start;
}
}
else
{
if(is_numeric($start) and is_numeric($end))
{
$this->limit = "{$start},{$end}";
}
}
return $this;
}
public function pagination($per_page)
{
if(is_numeric($per_page))
{
$this->per_page = $per_page;
$this->pagination_type = true;
}
return $this;
}
public function get()
{
$query = "SELECT {$this->select} FROM {$this->from}";
if(!is_null($this->where))
{
$query.=" where {$this->where}";
}
if(!is_null($this->group))
{
$query.=" group by {$this->group}";
}
if(!is_null($this->order))
{
$query.=" order by {$this->order}";
}
if($this->pagination_type)
{
$c_per_page = $this->per_page;
$c_arr = $this->get_arr;
$extra_query = preg_replace("#SELECT (.*?) FROM#","SELECT COUNT(*) as total_count FROM",$query);
$all = $this->query($extra_query,$this->get_arr);
if($all)
{
$total_count = $all->fetchAll(PDO::FETCH_ASSOC)[0]['total_count'];
$page_count = ceil($total_count/$c_per_page);
$current_page = (integer)m_u_g(DB_PAGINATION_GET) ? (integer)m_u_g(DB_PAGINATION_GET) : 1;
$current_limit=($current_page - 1) * $c_per_page;
$query = $query." limit {$current_limit},{$c_per_page}";
$current_rows = $this->query($query,$c_arr);
$data = $current_rows->fetchAll(PDO::FETCH_ASSOC);
$return = array();
$return['total_count'] = $total_count;
$return['current_count'] = count($data);
$return['total_page'] = $page_count;
$return['current_page'] = $current_page;
$return['data'] = $data;
return $return;
}
else
{
return false;
}
}
else
{
if(!is_null($this->limit))
{
$query.=" limit {$this->limit}";
}
$gets = $this->query($query,$this->get_arr);
if($gets)
{
$data = $gets->fetchAll(PDO::FETCH_ASSOC);
$return = array();
$return["total_count"] = count($data);
$return["data"] = $data;
return $return;
}
else
{
return false;
}
}
}
public function get_var($field)
{
if($this->m_empty($field))
{
return false;
}
else
{
$query = "SELECT {$field} FROM {$this->from}";
if(!is_null($this->where))
{
$query.=" where {$this->where}";
}
if(!is_null($this->order))
{
$query.=" order by id desc limit 1";
}
$gets = $this->query($query,$this->get_arr);
if($gets)
{
return $gets->fetchAll(PDO::FETCH_ASSOC)[0][$field];
}
else
{
return false;
}
}
}
public function get_vars($table,$where,$var,$type=true)
{
if($type)
{
$data = $this->connect->query("select $var from $table where $where order by id desc limit 1")->fetch(PDO::FETCH_ASSOC);
}
else
{
$data = $this->connect->query("select $var from $table where $where")->fetch(PDO::FETCH_ASSOC);
}
return $data["$var"];
}
public function count()
{
$grouped = false;
$query = "SELECT count(*) as total_count FROM {$this->from}";
if(!is_null($this->where))
{
$query.=" where {$this->where}";
}
if(!is_null($this->group))
{
$grouped = true;
$query.=" group by {$this->group}";
}
if(!is_null($this->order))
{
$query.=" order by {$this->order}";
}
$gets = $this->query($query,$this->get_arr);
if($gets)
{
if($grouped)
{
$count = 0;
foreach($gets->fetchAll(PDO::FETCH_ASSOC) as $counts)
{
$count = $count+$counts["total_count"];
}
return $count;
}
else
{
return $gets->fetch(PDO::FETCH_ASSOC)["total_count"];
}
}
else
{
return false;
}
}
public function insert(array $data)
{
if(is_array($data))
{
$query = 'INSERT INTO '.$this->from;
$keys = array_keys($data);
$query.=' ('.implode(',',$keys).') values (';
$query_add='';
$values = array_values($data);
foreach($values as $val)
{
$query_add.='?,';
}
$query_add = trim($query_add,',');
$query.=$query_add.')';
if($this->query($query,$values))
{
$this->last_id = $this->connect->lastInsertId();
return $this->last_id;
}
else
{
return false;
}
}
return false;
}
public function update(array $data)
{
if(is_array($data))
{
$query = "UPDATE {$this->from} set";
$keys = array_keys($data);
$values = array_values($data);
$query_add = '';
foreach($keys as $key)
{
$query_add.=" {$key} = ?,";
}
$query_add = trim($query_add,',');
$query.=$query_add;
if(!is_null($this->where))
{
$query.=" where {$this->where}";
}
$new = array_merge($values,$this->get_arr);
if($this->query($query,$new))
{
return true;
}
else
{
return false;
}
}
return false;
}
public function delete()
{
$query = "DELETE FROM {$this->from}";
if(!is_null($this->where))
{
$query.=" where {$this->where}";
}
if($this->query($query,$this->get_arr))
{
return true;
}
else
{
return false;
}
}
public function error()
{
return $this->error;
}
public function last_id()
{
return $this->last_id;
}
protected function reset()
{
$this->error = null;
$this->last_id = null;
$this->query = null;
$this->from = null;
$this->select = '*';
$this->where = null;
$this->group = null;
$this->order = null;
$this->limit = null;
$this->pagination_type = false;
$this->per_page = 0;
$this->get_arr = null;
}
}
$db = new DB();
?>```
解决方案
该问题是由在完成所需查询之前更改可变对象属性引起的Db::get()
。导致在类Db::$table
的同一实例上调用时更改属性Db
。
这是不鼓励使用 的最佳实践背后的原因之一global
,因为当前变量状态的意图/上下文不容易确定。
你的代码发生了什么是
Db::$table = 'rooms'
Db::$table = 'admin'
Db::$where = 'admin.id = 1'
Db::get() //SELECT * FROM admin WHERE admin.id = 1
Db::$table = null
Db::$where = null
Db::$where = 'rooms.id = 1'
Db::get() //SELECT * FROM WHERE rooms.id = 1
为避免此问题并确保所需的操作顺序,您需要Db::get()
在调用任何其他DB
修改调用时发出的查询属性的方法之前调用DB::get()
。
$roomId = example_function('id'); // (int) 1
//SELECT * FROM admin WHERE id = 1
$db->table('rooms')->where('id','=', $roomId)->get();
//SELECT * FROM rooms WHERE id = 1
或者,为了确保保留两个单独查询的意图,您需要DB
为第二个查询创建一个单独的实例。但是,这也会PDO
使用您当前的代码创建一个单独的实例。
为了避免第二个实例,PDO
您必须更改$this->connect
为静态属性并使用toself::$connect
重构任何方法。静态属性将确保每次调用时都只存在一个 PDO 实例。$this->connect
self::$connect
new Db()
class Db
{
protected static $connect;
//...
public function __construct()
{
try {
if (!isset(self::$connect)) {
self::$connect = new PDO("{$this->db_database}:host={$this->db_host};dbname={$this->db_name};charset=utf8mb4", "{$this->db_username}", "{$this->db_password}");
self::$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$connect->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8mb4");
}
} catch ( PDOException $e ){
echo "<b>Veritabanı bağlantısı sağlanamadı! - Hata Kodu: </b>".$e->getMessage();
exit;
}
}
//...
}
global $db;
然后将应用程序中的所有用法替换为$db = new Db();
.
这种方法还将确保您的整个代码库免受可变对象属性覆盖问题的影响,并更好地遵循最佳实践。
function example_function($key)
{
$db = new Db();
$a_id = 1; // example
$admins = $db->table('admins')->where('id','=',$a_id)->order('id','desc')->limit(1)->get();
$admin_data = $admins['data'][0];
$return = $admin_data[$key];
return $return;
}
$new = $db->table('rooms')->where('id','=', example_function('id'))->get();
另一种方法可能是用于clone
解决可变对象问题。但是,usingclone
会对PDO
instance产生不利影响,因为它位于Db
类中。很可能需要您将 PDO 连接代码与查询生成器代码分开。
function example_function($key)
{
global $db;
$db2 = clone $db;
$a_id = 1; // example
$admins = $db2->table('admins')->where('id','=',$a_id)->order('id','desc')->limit(1)->get();
//...
}
推荐阅读
- bash - 在比较列时打印具有差异的整行
- bash - 如何使用变量和星号打印正则表达式匹配列表
- java - Java Spark - 数据加密
- wordpress - 几个帖子中使用的 Wordpress 附件
- java - Spring data util对重命名json名称
- python - 为什么我的情节情节中有一条额外的线?
- sql - 如何连接来自选择查询的 oracle sql 输出
- c - 使用 ascii 将 C 中的字母大写
- xcode - 如何从具有不同捆绑标识符的应用程序访问 iCloud 容器数据?
- javascript - 用键“减少”嵌套数组到对象的最快方法 + 用键查找的最快方法