我正在编写一个自定义插件(定制,用于1个客户端,不用于发布和一般消费),需要访问自定义表。
一般来说,对于WP,我遵循的原则是在可能的情况下使用更高级别的API,因此很少需要使用\\wpdb。现在我确实有了需求,我发现它是多么古老!
通过查看源代码,我似乎可以确定它使用的是mysqli(因为插件需要php 7.1,我们也控制服务器),所以我想为什么不将其用于我的自定义表逻辑?
我写了一个小包装:
<?php
namespace PluginNamespaceHere\\DB;
use mysqli;
use wpdb;
/**
* A small wrapper class that contains, and provides direct access to, the $wpdb object,
* as well as the underlying MYSQLI object, so we can do real prepared statements etc
*/
class DB
{
/** @var wpdb */
public $wpdb;
/** @var mysqli */
public $mysqli;
/**
* @param wpdb $wpdb
*/
public function __construct(wpdb $wpdb)
{
$this->wpdb = $wpdb;
//$wpdb is protected, but accessible via magic __get() wp-db.php line: 643
$this->mysqli = $wpdb->dbh;
}
/**
* Run an SQL query. If $params are provided, prepared statements are used. If $bind_types are provided, they will be
* used in the prepared statement, if not, all params will be treated as strings
*
* @param string $sql The SQL string, unprefixed table names should be wrapped in curly braces eg SELECT * FROM {posts}
* @param array $params Optional parameters for prepared statements
* @param string $bind_types Optional bind types for prepared statements, defaults to string
* @retun bool|mysqli_result
*/
public function run($sql, $params=[], $bind_types=\'\')
{
$sql = $this->prefixTableNamesInSqlString($sql);
if(!is_array($params) || empty($params)){
return $this->mysqli->query($sql);
}
if($bind_types == \'\'){
$bind_types = str_repeat("s", count($params));
}
$stmt = $this->mysqli->prepare($sql);
$stmt->bind_param($bind_types, ...$params);
$stmt->execute();
return $stmt->get_result();
}
/**
* Replaces curly brace table names with their actual, prefixed name
* Eg "SELECT * from {table_name}" => "SELECT * from wp_table_name"
* @param string $sql
* @return string
*/
private function prefixTableNamesInSqlString($sql)
{
return str_replace(["{", "}"], [$this->wpdb->prefix, ""], $sql);
}
}
这将允许我使用真正准备好的查询,并具有良好的可读性代码,如:
<?php
$sql = "
SELECT DISTINCT c.ID AS course_id, c.post_title AS course_title
FROM {posts} c
JOIN {tmsc_course_product} cp
ON c.id = cp.course_id
WHERE cp.product_id IN(?,?)
";
//Yes, i know DB::run() can return bool! Out of scope for this question
$courses = $db->run($sql, [57,4761])->fetch_all(MYSQLI_ASSOC);
我唯一担心的是,这是否会对wpdb及其家属产生连锁效应。wpdb类并不容易阅读,而且似乎包含很多状态。