各位观众老爷,晚上好!今天咱来聊聊WordPress的骨骼——wp-db.php
,特别是其中那个神秘又强大的$wpdb
类。说它是骨骼,是因为WordPress几乎所有的数据操作都得通过它,没有它,WordPress就成了一堆漂亮的HTML代码,啥也干不了。
咱们今天的主题是$wpdb
类的数据库连接与SQL查询的底层封装。准备好了吗?咱们开始!
一、 $wpdb
:你的专属数据库管家
$wpdb
类,简单来说,就是WordPress为了方便开发者操作数据库而设计的一个类。它封装了数据库连接、查询、错误处理等等功能,让咱们可以不用直接跟MySQL打交道,而是通过它来完成各种数据库操作。
想象一下,如果没有$wpdb
,每次想查个文章标题,都得自己写一堆mysql_connect
、mysql_query
之类的代码,那得多麻烦啊!有了$wpdb
,咱们只需要调用几个简单的函数,就能轻松搞定。
二、 连接数据库:建立友谊的第一步
$wpdb
类最重要的功能之一就是建立数据库连接。WordPress在初始化的时候,会创建一个$wpdb
对象,并使用wp-config.php
中定义的数据库连接信息(DB_NAME
, DB_USER
, DB_PASSWORD
, DB_HOST
)来连接数据库。
先来看看$wpdb
类中几个关键的属性:
属性名 | 类型 | 描述 |
---|---|---|
dbuser |
string | 数据库用户名 |
dbpassword |
string | 数据库密码 |
dbname |
string | 数据库名称 |
dbhost |
string | 数据库主机地址 |
dbh |
resource | 数据库连接资源句柄 (通常是mysqli对象) |
query |
string | 最后一次执行的SQL查询语句 |
last_result |
array/object | 最后一次查询的结果集 (二维数组或对象数组,取决于查询方式) |
num_rows |
int | 最后一次查询影响的行数 |
last_error |
string | 最后一次查询的错误信息 |
prefix |
string | 表前缀 (在wp-config.php 中定义,用于区分不同的WordPress安装) |
queries |
array | 所有执行过的SQL查询语句的数组 (用于调试) |
query_times |
array | 每条SQL查询语句的执行时间数组 (用于性能分析) |
use_mysqli |
bool | 是否使用mysqli扩展 |
is_mysql |
bool | 是否是MySQL数据库 |
连接数据库的关键代码(简化版,实际代码更复杂):
class wpdb {
public $dbuser;
public $dbpassword;
public $dbname;
public $dbhost;
public $dbh; // Database handle
public $query;
public $last_result;
public $num_rows;
public $last_error;
public $prefix;
public $queries = array();
public $query_times = array();
public $use_mysqli = true;
public $is_mysql = true;
function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
$this->dbuser = $dbuser;
$this->dbpassword = $dbpassword;
$this->dbname = $dbname;
$this->dbhost = $dbhost;
$this->db_connect();
}
function db_connect() {
// Use mysqli if loaded
if ( function_exists( 'mysqli_connect' ) ) {
$this->use_mysqli = true;
$this->is_mysql = true;
$this->dbh = mysqli_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $this->dbname );
if ( !$this->dbh ) {
$this->bail( mysqli_connect_error() );
}
} else {
// Fallback to mysql (deprecated)
$this->use_mysqli = false;
$this->is_mysql = true;
$this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword );
if ( !$this->dbh ) {
$this->bail( mysql_error() );
}
if ( !mysql_select_db( $this->dbname, $this->dbh ) ) {
$this->bail( mysql_error() );
}
}
return $this->dbh;
}
function bail( $message ) {
echo '<h1>Database Error</h1>';
echo '<p>' . $message . '</p>';
die();
}
}
// 在WordPress初始化时,会创建 $wpdb 对象
global $wpdb;
$wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
这段代码的核心在于db_connect()
函数。它首先会检查是否安装了mysqli
扩展,如果安装了,就使用mysqli_connect()
函数来连接数据库;如果没有安装,就使用mysql_connect()
函数(注意:mysql_connect
函数已经过时,不建议使用)。如果连接失败,就调用bail()
函数来显示错误信息并终止程序。
三、 执行SQL查询:让数据为你跳舞
连接数据库之后,咱们就可以执行各种SQL查询了。$wpdb
类提供了多个函数来执行SQL查询,最常用的有:
query()
:执行任意SQL查询语句,返回受影响的行数。get_results()
:执行SQL查询语句,返回结果集(数组或对象)。get_row()
:执行SQL查询语句,返回结果集中的第一行(对象)。get_col()
:执行SQL查询语句,返回结果集中的第一列(数组)。get_var()
:执行SQL查询语句,返回结果集中的第一个字段的值。insert()
:插入数据到数据库表。update()
:更新数据库表中的数据。delete()
:删除数据库表中的数据。
咱们一个一个来看:
-
query()
:一锤定音query()
函数是最基础的查询函数,它可以执行任意SQL查询语句。它返回受影响的行数,如果查询失败,则返回false
。function query( $query ) { global $EZSQL_ERROR; $this->func_call = "$db->query("$query")"; // For reg expressions. $query = trim($query); // Log how the function was called. $this->call_dump[] = $this->func_call; // Keep track of the last query. $this->last_query = $query; // Reset error number. $this->last_error = ''; if ( defined('SAVEQUERIES') && SAVEQUERIES ) { $this->timer_start(); } // Perform the query via mysqli or mysql functions if ( $this->use_mysqli ) { $result = mysqli_query( $this->dbh, $query ); } else { $result = mysql_query( $query, $this->dbh ); } if ( defined('SAVEQUERIES') && SAVEQUERIES ) { $this->timer_stop(); $this->queries[] = $query; $this->query_times[] = $this->timer_elapsed; } // If there is an error then take note of it.. if ( $this->use_mysqli ) { if ( mysqli_error( $this->dbh ) ) { $this->last_error = mysqli_error( $this->dbh ); $this->print_error(); return false; } } else { if ( mysql_error( $this->dbh ) ) { $this->last_error = mysql_error( $this->dbh ); $this->print_error(); return false; } } // Query was an insert, delete, update, replace if ( preg_match("/^(insert|delete|update|replace)s+/i", $query) ) { $this->num_rows = ( $this->use_mysqli ) ? mysqli_affected_rows( $this->dbh ) : mysql_affected_rows( $this->dbh ); return $this->num_rows; } // Query was a select if ( $result ) { if ( $this->use_mysqli ) { $num_rows = mysqli_num_rows( $result ); } else { $num_rows = mysql_num_rows( $result ); } return $num_rows; // 返回查询结果的行数 } return false; // 查询失败 }
例如:
global $wpdb; $sql = "UPDATE {$wpdb->prefix}posts SET post_title = 'Hello World' WHERE ID = 1"; $result = $wpdb->query( $sql ); if ( $result !== false ) { echo "更新成功,影响了{$result}行"; } else { echo "更新失败,错误信息:{$wpdb->last_error}"; }
注意,
{$wpdb->prefix}
是WordPress表前缀,用于避免表名冲突。 -
get_results()
:满载而归get_results()
函数执行SQL查询语句,并返回结果集。它可以返回数组或对象,取决于你传递的参数。function get_results( $query = null, $output = OBJECT ) { global $EZSQL_ERROR; $return_val = array(); $this->func_call = "$db->get_results("$query, $output")"; // If there is a query then perform it if not then try to use last query. if ( $query ) { $this->query($query); } if ( $this->last_result ) { $i = 0; while ( $row = ( $this->use_mysqli ) ? mysqli_fetch_object( $this->result ) : mysql_fetch_object( $this->result ) ) { if ( $output == OBJECT ) { // Return an array of objects $return_val[$i] = $row; } elseif ( $output == ARRAY_A ) { // Return an array of associative arrays $return_val[$i] = (array) $row; } elseif ( $output == ARRAY_N ) { // Return an array of numbered arrays $return_val[$i] = array_values( (array) $row ); } else { $this->print_error(" $db->get_results(string query, output type); Output type must be one of: OBJECT, ARRAY_A, ARRAY_N"); } $i++; } if ( $i ) { $this->num_rows = $i; mysqli_free_result( $this->result ); // release memory return $return_val; } else { return null; } } else { return null; } }
$output
参数可以取以下值:OBJECT
(默认值):返回对象数组。ARRAY_A
:返回关联数组数组。ARRAY_N
:返回索引数组数组。
例如:
global $wpdb; $sql = "SELECT ID, post_title FROM {$wpdb->prefix}posts WHERE post_status = 'publish' LIMIT 10"; $posts = $wpdb->get_results( $sql ); if ( $posts ) { foreach ( $posts as $post ) { echo "{$post->ID}: {$post->post_title}<br>"; } } else { echo "没有找到文章"; }
如果
$output
设置为ARRAY_A
,那么访问文章标题的方式就变成了$post['post_title']
。 -
get_row()
:独占鳌头get_row()
函数执行SQL查询语句,并返回结果集中的第一行。它也可以返回对象、关联数组或索引数组,取决于你传递的参数。function get_row( $query = null, $output = OBJECT, $y = 0 ) { global $EZSQL_ERROR; $return_val = null; $this->func_call = "$db->get_row("$query, $output, $y")"; // If there is a query then perform it if not then try to use last query. if ( $query ) { $this->query($query); } if ( $this->last_result ) { if ( $output == OBJECT ) { // Return an object return @( $this->use_mysqli ) ? mysqli_fetch_object( $this->result ) : mysql_fetch_object( $this->result ); } elseif ( $output == ARRAY_A ) { // Return an associative array return @( $this->use_mysqli ) ? mysqli_fetch_assoc( $this->result ) : mysql_fetch_assoc( $this->result ); } elseif ( $output == ARRAY_N ) { // Return an numbered array return @( $this->use_mysqli ) ? mysqli_fetch_row( $this->result ) : mysql_fetch_row( $this->result ); } else { $this->print_error(" $db->get_row(string query, output type, int offset); Output type must be one of: OBJECT, ARRAY_A, ARRAY_N"); } } return $return_val; }
$output
参数的含义与get_results()
函数相同。$y
参数表示要返回的行号(从0开始),默认为0,即返回第一行。例如:
global $wpdb; $sql = "SELECT ID, post_title FROM {$wpdb->prefix}posts WHERE post_status = 'publish' ORDER BY ID DESC LIMIT 1"; $post = $wpdb->get_row( $sql ); if ( $post ) { echo "最新文章的ID是:{$post->ID},标题是:{$post->post_title}"; } else { echo "没有找到文章"; }
-
get_col()
:提取精华get_col()
函数执行SQL查询语句,并返回结果集中的第一列。它返回一个索引数组。function get_col( $query = null, $x = 0 ) { global $EZSQL_ERROR; $return_val = array(); $this->func_call = "$db->get_col("$query, $x")"; // If there is a query then perform it if not then try to use last query. if ( $query ) { $this->query($query); } if ( $this->last_result ) { $i = 0; while ( $row = ( $this->use_mysqli ) ? mysqli_fetch_row( $this->result ) : mysql_fetch_row( $this->result ) ) { $return_val[$i] = $row[$x]; $i++; } } if ( $return_val ) { mysqli_free_result( $this->result ); // release memory return $return_val; } else { return null; } }
$x
参数表示要返回的列号(从0开始),默认为0,即返回第一列。例如:
global $wpdb; $sql = "SELECT post_title FROM {$wpdb->prefix}posts WHERE post_status = 'publish' LIMIT 5"; $titles = $wpdb->get_col( $sql ); if ( $titles ) { foreach ( $titles as $title ) { echo $title . "<br>"; } } else { echo "没有找到文章标题"; }
-
get_var()
:一击命中get_var()
函数执行SQL查询语句,并返回结果集中的第一个字段的值。function get_var( $query = null, $x = 0, $y = 0 ) { global $EZSQL_ERROR; $this->func_call = "$db->get_var("$query, $x, $y")"; // If there is a query then perform it if not then try to use last query. if ( $query ) { $this->query($query); } if ( $this->last_result ) { $row = ( $this->use_mysqli ) ? mysqli_fetch_row( $this->result ) : mysql_fetch_row( $this->result ); if( isset( $row[$x] ) ) { mysqli_free_result( $this->result ); // release memory return $row[$x]; } else { return null; } } else { return null; } }
$x
参数表示要返回的列号(从0开始),默认为0,即返回第一列。$y
参数表示要返回的行号(从0开始),默认为0,即返回第一行。例如:
global $wpdb; $sql = "SELECT COUNT(*) FROM {$wpdb->prefix}posts WHERE post_status = 'publish'"; $count = $wpdb->get_var( $sql ); echo "共有{$count}篇已发布的文章";
-
insert()
、update()
、delete()
:增删改查这三个函数分别用于插入、更新和删除数据。它们都接受一个表名和一个包含数据的数组作为参数。
function insert( $table, $data, $format = null ) { return $this->replace( $table, $data, $format, 'INSERT' ); } function update( $table, $data, $where, $format = null, $where_format = null ) { return $this->replace( $table, $data, $where, 'UPDATE', $format, $where_format ); } function delete( $table, $where, $where_format = null ) { $q = "DELETE FROM `$table`"; $q .= ' WHERE ' . $this->prepare_where( $where, $where_format ); return $this->query( $q ); }
例如:
global $wpdb; // 插入数据 $data = array( 'post_title' => 'New Post', 'post_content' => 'This is the content of the new post.', 'post_status' => 'draft', 'post_date' => current_time( 'mysql' ) ); $wpdb->insert( $wpdb->prefix . 'posts', $data ); $new_post_id = $wpdb->insert_id; // 获取插入的ID // 更新数据 $data = array( 'post_title' => 'Updated Post Title' ); $where = array( 'ID' => $new_post_id ); $wpdb->update( $wpdb->prefix . 'posts', $data, $where ); // 删除数据 $where = array( 'ID' => $new_post_id ); $wpdb->delete( $wpdb->prefix . 'posts', $where );
注意,
$wpdb->insert_id
可以获取最后一次插入操作的ID。
四、 prepare()
:安全第一
在使用$wpdb
进行数据库操作时,一定要注意SQL注入的风险。为了避免SQL注入,可以使用$wpdb->prepare()
函数来对SQL语句进行预处理。
function prepare( $query, ...$args ) {
if ( is_null( $query ) ) {
return;
}
$args = func_get_args();
array_shift( $args ); // 将 $query 从参数列表中移除
if ( is_array( $args[0] ) ) {
$args = $args[0];
}
$query = str_replace( "'%s'", '%s', $query ); // strip single quotes
$query = str_replace( '"%s"', '%s', $query ); // strip double quotes
$query = str_replace( "'%d'", '%d', $query ); // strip single quotes
$query = str_replace( '"%d"', '%d', $query ); // strip double quotes
$query = str_replace( '%s', "'%s'", $query ); // quote the strings, avoiding escaped strings like '%s'
$query = str_replace( '%d', "'%d'", $query ); // quote the digits, avoiding escaped strings like '%d'
$args = array_map( array( $this, 'esc_like' ), $args );
return vsprintf( $query, array_map( array( $this, '_real_escape' ), $args ) );
}
prepare()
函数的用法是:
global $wpdb;
$sql = $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}posts WHERE post_title = %s AND post_status = %s",
'Hello World',
'publish'
);
$posts = $wpdb->get_results( $sql );
%s
表示字符串,%d
表示数字。prepare()
函数会将这些占位符替换为实际的值,并对这些值进行转义,从而避免SQL注入。
五、 错误处理:有备无患
$wpdb
类提供了错误处理机制,可以通过$wpdb->last_error
属性获取最后一次查询的错误信息。
global $wpdb;
$sql = "SELECT * FROM non_existent_table";
$wpdb->query( $sql );
if ( $wpdb->last_error ) {
echo "查询出错:{$wpdb->last_error}";
}
六、 总结:掌握核心,玩转数据
今天咱们深入了解了$wpdb
类的数据库连接与SQL查询的底层封装。 掌握了这些知识,你就可以更加灵活地操作WordPress数据库,实现各种各样的功能。
记住,$wpdb
是你的专属数据库管家,善用它,让数据为你跳舞!
今天的讲座就到这里,感谢各位观众老爷的捧场!下次再见!