分析 WordPress `wpdb` 类的 `get_results()` 方法的源码:如何处理查询结果并将其转换为对象数组。

各位观众老爷,晚上好!今天咱们来聊聊 WordPress 数据库交互的核心角色——wpdb 类的 get_results() 方法,尤其是它如何把冷冰冰的数据库数据变成暖乎乎的对象数组,方便我们后续操作。

开场白:数据变形记,从SQL到对象

想象一下,你给数据库发了个指令(SQL 查询),它吭哧吭哧给你吐了一堆数据回来。这些数据就像杂乱无章的零件,需要我们组装成特定的模型。wpdb 类的 get_results() 方法就是这个组装大师,它负责把数据库返回的原始结果,按照你的需求,变成更容易使用的对象数组、关联数组等等。而对象数组,则是最常用的变形方式之一。

一、get_results() 方法的庐山真面目

首先,咱们来扒一扒 get_results() 方法的源码,看看它到底长啥样。

public function get_results( $query = null, $output = OBJECT ) {
    global $wp_object_cache;

    $this->func_call = __FUNCTION__;

    if ( $query ) {
        $this->last_query = $query;
    }

    // Bail early if there is no query to execute.
    if ( empty( $this->last_query ) ) {
        return null;
    }

    // Raw query results.
    $this->result = null;

    // Take note of the call time.
    $this->timer_start();

    // Use cache if available.
    if ( $this->use_mysqli ) {
        $cache_key = md5( $this->last_query );
        $cache_group = 'mysqli-query';

        if ( is_object( $wp_object_cache ) && $this->use_cache && isset( $wp_object_cache->cache[ $cache_group ][ $cache_key ] ) ) {
            $this->num_queries++;
            $this->queries[] = $this->last_query;
            $this->query_times[] = $wp_object_cache->cache[ $cache_group ][ $cache_key ]['time'];
            return $wp_object_cache->cache[ $cache_group ][ $cache_key ]['data'];
        }
    }

    // If a transactional query is in process, hold off on caching.
    if ( $this->in_transaction ) {
        $this->suppress_cache = true;
    }

    // Run the query.
    $this->result = @mysqli_query( $this->dbh, $this->last_query );

    $this->timer_stop();

    $this->num_queries++;
    $this->queries[] = $this->last_query;
    $this->query_times[] = $this->timer_elapsed;

    // If there is an error then handle it.
    if ( $this->last_error ) {
        $this->print_error();
        return false;
    }

    $this->num_rows = 0;

    // If asking for raw results, return the mysql result.
    if ( strtoupper( $output ) === OBJECT_K ) {
      return $this->result;
    }

    // Store Query Results
    if ( $this->result ) {
        if ( is_object( $wp_object_cache ) && $this->use_cache && !$this->suppress_cache ) {
            $cache_data = array();
        }

        while ( $row = @mysqli_fetch_object( $this->result ) ) {
            $this->num_rows++;
            $results[] = $row;

            if ( is_object( $wp_object_cache ) && $this->use_cache && !$this->suppress_cache ) {
                $cache_data[] = $row;
            }
        }

        @mysqli_free_result( $this->result );

        if ( is_object( $wp_object_cache ) && $this->use_cache && !$this->suppress_cache ) {
            $wp_object_cache->cache[ $cache_group ][ $cache_key ] = array(
                'time' => $this->timer_elapsed,
                'data' => $cache_data,
            );
        }

        // If returning a single row, return an object instead of an array.
        if ( 'OBJECT' == $output && 1 == $this->num_rows ) {
            return $results[0];
        }

        if ( empty( $results ) ) {
            return array();
        }

        return $results;
    } else {
        return null;
    }
}

别被这一大坨代码吓着,咱们一点点拆解。

二、流程分解:从查询到对象数组

get_results() 方法的主要工作流程可以概括为以下几个步骤:

  1. 接收查询语句和输出类型: 接受 SQL 查询语句($query)和输出类型($output)。默认输出类型是 OBJECT,也就是对象数组。
  2. 查询缓存(可选): 如果开启了缓存,并且缓存中存在对应查询的结果,则直接从缓存中返回,避免重复查询数据库。
  3. 执行查询: 使用 mysqli_query() 函数执行 SQL 查询,获取数据库返回的原始结果集。
  4. 处理结果集: 这是最关键的一步,get_results() 方法会遍历结果集,并将每一行数据转换为对象,然后将这些对象放入一个数组中。
  5. 返回结果: 根据输出类型($output)返回最终结果。如果 $outputOBJECT,则返回对象数组。

三、核心代码剖析:mysqli_fetch_object() 的妙用

现在,咱们把目光聚焦到处理结果集的核心代码:

while ( $row = @mysqli_fetch_object( $this->result ) ) {
    $this->num_rows++;
    $results[] = $row;

    if ( is_object( $wp_object_cache ) && $this->use_cache && !$this->suppress_cache ) {
        $cache_data[] = $row;
    }
}

这段代码是把原始数据变成对象数组的关键。mysqli_fetch_object() 函数闪亮登场!

  • mysqli_fetch_object( $this->result ) 这个函数的作用是从结果集中取出一行数据,并将其转换为一个 对象。对象的属性名对应数据库表的字段名,属性值对应字段的值。

    例如,如果你的数据库表 wp_postsIDpost_titlepost_content 这几个字段,那么 mysqli_fetch_object() 返回的对象就会有 $post->ID$post->post_title$post->post_content 这几个属性。

  • $results[] = $row; 将取出的对象 $row 添加到 $results 数组中。这样,循环结束后,$results 数组就包含了所有查询结果转换成的对象。

四、输出类型:$output 参数的选择

get_results() 方法的 $output 参数决定了返回结果的类型。它有以下几种取值:

输出类型 常量 返回值
OBJECT OBJECT 对象数组。每个元素都是一个对象,对象的属性对应数据库表的字段名和值。这是默认的输出类型。
ARRAY_A ARRAY_A 关联数组数组。每个元素都是一个关联数组,数组的键名对应数据库表的字段名,键值对应字段的值。
ARRAY_N ARRAY_N 索引数组数组。每个元素都是一个索引数组,数组的索引对应数据库表的字段顺序,数组的值对应字段的值。
OBJECT_K OBJECT_K 谨慎使用:返回原始的 MySQLi 结果对象。这种方式直接返回 mysqli_query() 的结果,需要手动使用 mysqli_fetch_object() 等函数来处理结果集。通常不建议直接使用这种方式,因为它绕过了 wpdb 类的封装,代码可读性和可维护性较差。 同时,wpdb 类通常会在使用完结果对象后进行释放资源,如果直接返回 OBJECT_K ,可能会导致后续使用该结果对象时出现问题。建议使用其他的输出类型,例如 OBJECTARRAY_AARRAY_N,因为这些类型已经封装了结果集的处理,并返回更易于使用的数据结构。

五、实战演练:代码示例

为了更好地理解 get_results() 方法的使用,咱们来看几个代码示例。

示例 1:获取所有文章的标题

global $wpdb;

$query = "SELECT post_title FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type = 'post'";
$posts = $wpdb->get_results( $query );

if ( $posts ) {
    foreach ( $posts as $post ) {
        echo $post->post_title . '<br>';
    }
}

这段代码会查询 wp_posts 表中所有已发布的文章的标题,并将结果以对象数组的形式返回。然后,遍历对象数组,输出每个文章的标题。

示例 2:获取指定文章的 ID 和标题,并以关联数组的形式返回

global $wpdb;

$post_id = 123;
$query = $wpdb->prepare( "SELECT ID, post_title FROM {$wpdb->posts} WHERE ID = %d", $post_id );
$post = $wpdb->get_results( $query, ARRAY_A );

if ( $post ) {
    echo '文章 ID:' . $post[0]['ID'] . '<br>';
    echo '文章标题:' . $post[0]['post_title'] . '<br>';
}

这段代码会查询 wp_posts 表中 ID 为 123 的文章的 ID 和标题,并将结果以关联数组数组的形式返回。注意,这里使用了 $wpdb->prepare() 函数来防止 SQL 注入。

示例 3:使用 OBJECT_K (不推荐,仅作演示)

global $wpdb;

$query = "SELECT * FROM {$wpdb->posts} WHERE post_status = 'publish' LIMIT 1";
$result = $wpdb->get_results( $query, OBJECT_K );

if ($result) {
    // 使用 mysqli_fetch_object 手动处理结果
    $row = mysqli_fetch_object($result);

    if ($row) {
        echo "Post Title: " . $row->post_title;
    }

    // 记得释放结果集资源
    mysqli_free_result($result);
}

六、注意事项:SQL 注入和性能优化

在使用 get_results() 方法时,需要注意以下几点:

  1. 防止 SQL 注入: 永远不要直接将用户输入的数据拼接到 SQL 查询语句中。使用 $wpdb->prepare() 函数来对用户输入的数据进行转义,防止 SQL 注入攻击。
  2. 性能优化: 尽量避免执行复杂的 SQL 查询。可以使用 WordPress 内置的查询函数(例如 get_posts())来简化查询操作。如果需要执行自定义查询,可以考虑使用缓存来减少数据库查询次数。

七、总结:get_results() 方法的价值

wpdb 类的 get_results() 方法是 WordPress 数据库交互的核心方法之一。它提供了一种方便的方式来执行 SQL 查询,并将查询结果转换为对象数组、关联数组等易于使用的数据结构。通过合理地使用 get_results() 方法,可以轻松地从 WordPress 数据库中获取所需的数据,并将其应用于各种 WordPress 开发场景中。

掌握 get_results() 方法,就像掌握了一把开启 WordPress 数据库大门的钥匙。希望今天的讲解能帮助你更好地理解和使用这个强大的工具。

八、进阶思考:wp_queryget_results 的区别

很多同学可能会疑惑,wp_queryget_results 都是查询数据的,它们有什么区别呢?

简单来说,wp_query 是 WordPress 专门用于查询文章(post)的类,它封装了更高级的功能,例如分页、排序、分类等等。而 get_results 则是一个更通用的数据库查询方法,可以查询任何表,返回任何类型的数据。

特性 WP_Query wpdb->get_results()
主要用途 查询文章(posts),支持复杂的文章查询条件。 执行任意 SQL 查询,不限于文章。
核心功能 文章循环、分页、taxonomy 查询、meta 查询等。 执行 SQL 查询,结果集处理。
使用场景 需要展示文章列表、文章详情等与文章相关的场景。 需要自定义 SQL 查询,访问非文章表,或者执行复杂查询的场景。
性能 针对文章查询进行了优化,但复杂的 WP_Query 也可能影响性能。 性能取决于 SQL 查询的效率。
安全性 内置了一些安全机制,例如参数过滤。 需要开发者自行处理 SQL 注入等安全问题。

你可以把 wp_query 看作是建立在 get_results 之上的一个更高级的封装。如果你只需要查询文章,并且需要使用 WordPress 内置的功能(例如分页),那么 wp_query 是更好的选择。如果你需要执行自定义的 SQL 查询,或者查询非文章表,那么 get_results 更加灵活。

今天的讲座就到这里,希望大家有所收获!下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注