剖析 `wpdb` 类的 `query_as_array()` 方法源码,它是如何将查询结果转换为关联数组的?

各位观众老爷,大家好!我是今天的主讲人,老码农小李。今天咱们来聊聊 WordPress 里面那个神秘又常用的 wpdb 类,特别是它的 query_as_array() 方法。这玩意儿能把数据库查询结果变成咱们熟悉的关联数组,用起来那叫一个顺手。

咱们今天的目标就是:扒开它的底裤,看看它到底是怎么运作的!

一、wpdb 类,你是谁?

在深入 query_as_array() 之前,咱们先简单认识一下 wpdb 类。你可以把它想象成 WordPress 访问数据库的“总代理”。它封装了各种数据库操作,让你不用直接写那些复杂的 SQL 语句(当然,如果你喜欢,也可以直接写)。

wpdb 类提供了很多方法,比如 query()get_results()get_row() 等等,它们的功能各不相同,但最终目的都是为了从数据库里捞数据。

二、query_as_array():化腐朽为神奇

query_as_array() 方法,顾名思义,就是把查询结果转换成数组的。更准确地说,是关联数组,也就是可以用字段名作为键来访问数据的数组。

它的基本用法是这样的:

global $wpdb;
$results = $wpdb->query_as_array("SELECT * FROM wp_posts LIMIT 10");

if ($results) {
  foreach ($results as $row) {
    echo "Post Title: " . $row['post_title'] . "<br>";
    echo "Post Content: " . $row['post_content'] . "<br>";
  }
} else {
  echo "No posts found.";
}

这段代码会从 wp_posts 表里取出前 10 条记录,然后把每条记录都转换成一个关联数组,方便你直接通过字段名访问数据。

三、源码剖析:一层一层扒开你的心

好了,废话不多说,直接上源码!(以下代码基于 WordPress 6.3.1 版本,不同版本可能会有细微差异):

/**
 * Perform a query and return the entire result set as an array of associative arrays.
 *
 * This is a wrapper around {@see wpdb::get_results()}.
 *
 * @since 5.5.0
 *
 * @param string|null $query   Optional. The SQL query to execute. Can be null to return the last query results.
 *                             Default null.
 * @param int         $output  Optional. The required return type. One of ARRAY_A, ARRAY_N, or OBJECT.
 *                             Default ARRAY_A.
 * @param int         $y       Optional. Offset of the returned row. Default 0.
 * @return array|null An array of associative arrays representing the query result.
 *                    Null if there is an error or no rows were returned.
 */
public function query_as_array( ?string $query = null, int $output = ARRAY_A, int $y = 0 ) {
    return $this->get_results( $query, $output, $y );
}

看到没?query_as_array() 实际上只是 get_results() 方法的一个“马甲”!它只是简单地把 output 参数设置成了 ARRAY_A,然后调用了 get_results()

所以,咱们的重点就转移到 get_results() 方法上了。

/**
 * Perform a query and return the entire result set as an array.
 *
 * By default, returns an array of associative arrays, as in
 * {@link https://www.php.net/mysqli_fetch_assoc mysqli_fetch_assoc()}.
 *
 * @since 2.0.0
 * @since 3.5.0 The `$output` parameter accepts OBJECT, ARRAY_A, or ARRAY_N.
 *
 * @global wpdb $wpdb WordPress database abstraction object.
 *
 * @param string|null $query   Optional. The SQL query to execute. Can be null to return the last query results.
 *                             Default null.
 * @param string      $output  Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N.
 *                             Default OBJECT.
 * @param int         $y       Optional. Offset of the returned row. Default 0.
 * @return array|object|null An array of results (usually associative arrays), null if there is an error.
 */
public function get_results( ?string $query = null, string $output = OBJECT, int $y = 0 ) {
    global $wpdb;

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

    // Set the query to execute.
    if ( empty( $query ) ) {
        $query = $this->last_query;
    }

    // Clear the last result.
    $this->last_result = null;

    // Execute the query.
    $result = $this->query( $query );

    // Bail if there is an error.
    if ( ! $result ) {
        return null;
    }

    // Initialize variables to store the results.
    $i        = 0;
    $j        = 0;
    $num_rows = $this->num_rows;

    // If there are rows to return.
    if ( $num_rows ) {
        $this->last_result = array();

        // Move the internal data pointer to the start of the result set.
        if ( $y != 0 ) {
            mysqli_data_seek( $this->dbh, $y );
        }

        // Fetch the results.
        while ( $i < $num_rows ) {
            if ( $output == OBJECT ) {
                $this->last_result[ $i ] = mysqli_fetch_object( $this->dbh );
            } elseif ( $output == ARRAY_A ) {
                $this->last_result[ $i ] = mysqli_fetch_assoc( $this->dbh );
            } elseif ( $output == ARRAY_N ) {
                $this->last_result[ $i ] = mysqli_fetch_row( $this->dbh );
            } else {
                $this->last_result[ $i ] = mysqli_fetch_object( $this->dbh );
            }

            if ( $y != 0 && $i == $y ) {
                break;
            }

            $i++;
        }

        // If we want a single row, return it.
        if ( $i == 1 && ! empty( $this->last_result ) ) {
            $this->last_result = $this->last_result[0];
        }

        mysqli_free_result( $this->dbh );
    }

    // Return null if there is no result.
    if ( empty( $this->last_result ) ) {
        return null;
    }

    // Return the result.
    return $this->last_result;
}

好家伙,代码有点长,咱们一点一点分析:

  1. 参数处理:

    • $query:要执行的 SQL 查询语句。如果没有传入,就使用上次执行的查询语句。
    • $output:指定返回结果的类型。它可以是 OBJECT(对象)、ARRAY_A(关联数组)或 ARRAY_N(数字索引数组)。 重点是,query_as_array() 调用 get_results() 的时候,把这个参数设置成了 ARRAY_A
    • $y:结果集的偏移量,表示从哪一行开始获取数据。
  2. 执行查询:

    • $result = $this->query( $query );:这行代码调用 wpdb 类的 query() 方法来执行 SQL 查询。query() 方法负责连接数据库,发送 SQL 语句,并返回执行结果。
    • 如果查询失败,get_results() 会直接返回 null
  3. 处理查询结果:

    • $num_rows = $this->num_rows;:获取查询结果的行数。
    • 如果查询结果有数据,get_results() 会进入一个 while 循环,逐行处理结果集。
    • 关键就在这里:mysqli_fetch_assoc( $this->dbh );。这行代码使用 PHP 的 mysqli_fetch_assoc() 函数从结果集中获取一行数据,并将其转换成一个关联数组。 $this->dbh 是数据库连接句柄。
    参数 说明
    $this->dbh 数据库连接句柄,指向当前连接的 MySQLi 资源。
    mysqli_fetch_assoc() 从结果集中获取下一行数据,并将其作为关联数组返回。数组的键是列名,值是对应列的值。 如果结果集中没有更多行,则返回 null
    • $this->last_result[ $i ] = mysqli_fetch_assoc( $this->dbh );:将获取到的关联数组存储到 $this->last_result 数组中。
    • 如果 $output 参数是 OBJECT,则使用 mysqli_fetch_object() 函数获取对象;如果 $output 参数是 ARRAY_N,则使用 mysqli_fetch_row() 函数获取数字索引数组。
    • 循环结束后,$this->last_result 数组就包含了所有查询结果,每个元素都是一个关联数组。
  4. 返回结果:

    • get_results() 方法最终会返回 $this->last_result 数组。

四、mysqli_fetch_assoc():幕后英雄

现在,咱们来重点分析一下 mysqli_fetch_assoc() 函数。这个函数是 PHP 内置的,用于从 MySQLi 结果集中获取一行数据,并将其转换为关联数组。

它的工作原理很简单:

  1. 接收一个 MySQLi 结果集资源作为参数。
  2. 从结果集中读取下一行数据。
  3. 将每一列的数据以键值对的形式存储到一个数组中,其中键是列名,值是对应列的值。
  4. 返回这个数组。
  5. 如果结果集中没有更多行,则返回 null

举个例子,假设你执行了以下 SQL 查询:

SELECT id, name, email FROM users WHERE id = 1;

查询结果如下:

id name email
1 John Doe [email protected]

那么,mysqli_fetch_assoc() 函数会将这行数据转换成以下关联数组:

array(
  'id' => '1',
  'name' => 'John Doe',
  'email' => '[email protected]'
)

五、总结:query_as_array() 的工作流程

现在,咱们可以总结一下 query_as_array() 方法的工作流程了:

  1. query_as_array() 接收一个 SQL 查询语句作为参数。
  2. query_as_array()output 参数设置为 ARRAY_A,并调用 get_results() 方法。
  3. get_results() 方法执行 SQL 查询,并获取查询结果。
  4. get_results() 方法使用 mysqli_fetch_assoc() 函数逐行处理查询结果,将每一行数据转换成一个关联数组。
  5. get_results() 方法将所有关联数组存储到一个数组中,并返回该数组。
  6. query_as_array() 方法将 get_results() 方法返回的数组作为自己的返回值。

简单来说,query_as_array() 就是 get_results() 方法的一个“快捷方式”,它帮你省去了设置 output 参数的麻烦。

六、注意事项:一些坑需要避开

  • 性能问题: 如果查询结果集非常大,query_as_array() 可能会占用大量的内存。在这种情况下,可以考虑使用迭代器或者分页查询来减少内存消耗。
  • 安全性问题: 在使用 query_as_array() 方法时,一定要注意 SQL 注入攻击。不要直接将用户输入的数据拼接到 SQL 语句中,而是应该使用 wpdb 类的 prepare() 方法来对 SQL 语句进行转义。
  • 错误处理: 在使用 query_as_array() 方法时,一定要进行错误处理。如果查询失败,query_as_array() 会返回 null,你需要检查返回值是否为 null,并根据情况进行处理。

七、高级用法:更上一层楼

除了基本用法之外,query_as_array() 还有一些高级用法,可以让你更灵活地处理查询结果:

  • 指定偏移量: 你可以使用 $y 参数来指定结果集的偏移量,从而只获取部分数据。
  • 自定义处理: 你可以自定义一个函数来处理每一行数据,并将处理后的结果存储到数组中。

八、实例演示:代码才是王道

为了更好地理解 query_as_array() 方法,咱们来看几个实例:

实例 1:获取指定 ID 的文章标题

global $wpdb;
$post_id = 123;
$query = $wpdb->prepare("SELECT post_title FROM wp_posts WHERE ID = %d", $post_id);
$results = $wpdb->query_as_array($query);

if ($results) {
  echo "Post Title: " . $results[0]['post_title'] . "<br>";
} else {
  echo "Post not found.";
}

实例 2:获取所有文章的 ID 和标题,并存储到数组中

global $wpdb;
$query = "SELECT ID, post_title FROM wp_posts";
$results = $wpdb->query_as_array($query);

$posts = array();
if ($results) {
  foreach ($results as $row) {
    $posts[$row['ID']] = $row['post_title'];
  }
}

print_r($posts);

实例 3:使用偏移量获取部分文章

global $wpdb;
$offset = 10;
$limit = 5;
$query = "SELECT ID, post_title FROM wp_posts LIMIT $offset, $limit";
$results = $wpdb->query_as_array($query);

if ($results) {
  foreach ($results as $row) {
    echo "Post ID: " . $row['ID'] . ", Post Title: " . $row['post_title'] . "<br>";
  }
} else {
  echo "No posts found.";
}

九、总结:掌握 query_as_array(),走遍天下都不怕

好了,今天的讲座就到这里。希望通过今天的讲解,你已经对 wpdb 类的 query_as_array() 方法有了更深入的了解。掌握了这个方法,你就可以更轻松地从 WordPress 数据库中获取数据,并将其转换成你需要的格式。

记住,代码才是王道!多写代码,多实践,你才能真正掌握这些知识。

下次有机会,咱们再聊聊 wpdb 类的其他方法。再见!

发表回复

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