阐述 WordPress `get_transient()` 函数的源码:如何利用 `wp_options` 表和过期时间实现短暂缓存。

各位观众,晚上好!今天咱们来聊聊 WordPress 里的一个神秘小助手:get_transient()。 别看它名字平平无奇,其实它可是 WordPress 短暂缓存的秘密武器。 想象一下,你写了一个查询数据库,或者调用了外部 API 的代码。 每次用户访问页面都要重新执行一遍,那服务器岂不是要累趴下? 这时候,get_transient() 就派上用场了,它可以把结果缓存起来,下次再访问直接拿缓存,速度嗖嗖的!

咱们今天就来扒一扒 get_transient() 的源码,看看它是怎么利用 wp_options 表和过期时间来实现这个短暂缓存的。 准备好了吗? Let’s dive in!

1. 什么是 Transient?

首先,咱们得搞清楚什么是 "Transient"。 简单来说,Transient 就是 "短暂的、临时的" 数据。 这种数据不需要永久保存,过一段时间就可以丢弃。 比如,一个统计最近24小时访问量的结果,或者一个从第三方 API 获取的数据,这些都适合用 Transient 来缓存。

2. get_transient() 的基本用法

在 WordPress 中,get_transient() 函数用于从缓存中获取 Transient 数据。 它的基本用法如下:

$transient_name = 'my_awesome_transient';
$transient_value = get_transient( $transient_name );

if ( false === $transient_value ) {
    // 缓存不存在,需要重新计算或获取数据
    $transient_value = calculate_something_expensive(); // 假设这是一个耗时的操作

    // 将数据存入缓存,设置过期时间为 1 小时 (3600 秒)
    set_transient( $transient_name, $transient_value, 3600 );
}

// 使用缓存数据
echo "The value is: " . $transient_value;

这段代码的意思是:

  1. 先尝试从缓存中获取名为 my_awesome_transient 的数据。
  2. 如果缓存不存在(返回 false),就执行耗时的操作 calculate_something_expensive() 获取数据。
  3. 然后,使用 set_transient() 函数将数据存入缓存,并设置过期时间为 1 小时。
  4. 最后,使用缓存中的数据。

3. 源码剖析:get_transient() 的真面目

好了,现在咱们开始深入 get_transient() 的源码,看看它到底是怎么工作的。 get_transient() 函数位于 wp-includes/functions.php 文件中。

function get_transient( $transient ) {
    /**
     * Fires before a specific transient is retrieved.
     *
     * @since 3.0.0
     *
     * @param string $transient Transient name.
     */
    do_action( 'pre_get_transient_' . $transient );

    $transient_option = '_transient_' . $transient;
    $value = get_option( $transient_option );

    if ( false === $value ) {
        /**
         * Fires after a specific transient is retrieved but its value is empty.
         *
         * @since 3.0.0
         *
         * @param string $transient Transient name.
         */
        do_action( 'get_transient_' . $transient );

        return false;
    }

    $expiration = get_option( '_transient_timeout_' . $transient );

    if ( false !== $expiration && time() > $expiration ) {
        delete_transient( $transient );

        /**
         * Fires after a specific transient is retrieved but is expired.
         *
         * @since 3.0.0
         *
         * @param string $transient Transient name.
         */
        do_action( 'get_transient_' . $transient . '_expired' );

        return false;
    }

    /**
     * Filters the value of an existing transient.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 3.0.0
     *
     * @param mixed $value Transient value.
     * @param string $transient Transient name.
     */
    return apply_filters( 'get_transient_' . $transient, $value, $transient );
}

让我们一行一行地解读这段代码:

  1. do_action( 'pre_get_transient_' . $transient );: 这是一个 action hook,允许开发者在获取 Transient 之前执行一些操作。 比如,可以用来记录 Transient 的访问日志。
  2. $transient_option = '_transient_' . $transient;: 这是 Transient 数据的 Option Name。 WordPress 使用 wp_options 表来存储 Transient 数据,每个 Transient 都有一个唯一的 Option Name。 这个 Option Name 的格式是 _transient_ 前缀加上 Transient 的名字。 比如,如果 Transient 的名字是 my_awesome_transient,那么 Option Name 就是 _transient_my_awesome_transient
  3. $value = get_option( $transient_option );: 这里使用 get_option() 函数从 wp_options 表中获取 Transient 数据。 get_option() 函数是 WordPress 提供的一个用于获取 Option 值的函数。
  4. if ( false === $value ) { ... }: 如果 get_option() 函数返回 false,说明缓存不存在。 此时,会触发一个 action hook get_transient_$transient,然后返回 false
  5. $expiration = get_option( '_transient_timeout_' . $transient );: 这里获取 Transient 的过期时间。 同样,过期时间也存储在 wp_options 表中,Option Name 的格式是 _transient_timeout_ 前缀加上 Transient 的名字。
  6. if ( false !== $expiration && time() > $expiration ) { ... }: 如果过期时间存在,并且当前时间已经超过了过期时间,说明缓存已经过期。 此时,会调用 delete_transient() 函数删除缓存,触发一个 action hook get_transient_$transient_expired,然后返回 false
  7. return apply_filters( 'get_transient_' . $transient, $value, $transient );: 如果缓存存在且未过期,就使用 apply_filters() 函数对缓存数据进行过滤,然后返回。 这是一个 filter hook,允许开发者修改缓存数据。

4. set_transient() 的源码分析

set_transient() 函数用于设置 Transient 数据。 它的源码如下:

function set_transient( $transient, $value, $expiration = 0 ) {
    /**
     * Fires before a specific transient is set.
     *
     * @since 3.0.0
     *
     * @param string $transient  Transient name.
     * @param mixed  $value      Transient value.
     * @param int    $expiration Time until expiration in seconds.
     */
    do_action( 'pre_set_transient_' . $transient, $value, $expiration );

    $transient_timeout = '_transient_timeout_' . $transient;
    $transient_option  = '_transient_' . $transient;

    if ( false === get_transient( $transient ) ) {
        if ( 0 < $expiration ) {
            set_option( $transient_timeout, time() + $expiration, false );
            add_option( $transient_option, $value, '', 'no' );
        } else {
            delete_option( $transient_timeout );
            add_option( $transient_option, $value, '', 'no' );
        }
    } else {
        if ( 0 < $expiration ) {
            update_option( $transient_timeout, time() + $expiration, false );
            update_option( $transient_option, $value, false );
        } else {
            delete_option( $transient_timeout );
            update_option( $transient_option, $value, false );
        }
    }

    /**
     * Fires after a specific transient is set.
     *
     * @since 3.0.0
     *
     * @param string $transient  Transient name.
     * @param mixed  $value      Transient value.
     * @param int    $expiration Time until expiration in seconds.
     */
    do_action( 'set_transient_' . $transient, $value, $expiration );

    return true;
}

这段代码的逻辑如下:

  1. do_action( 'pre_set_transient_' . $transient, $value, $expiration );: 这是一个 action hook,允许开发者在设置 Transient 之前执行一些操作。
  2. $transient_timeout = '_transient_timeout_' . $transient;$transient_option = '_transient_' . $transient;: 分别定义了过期时间和数据的 Option Name。
  3. if ( false === get_transient( $transient ) ) { ... }: 判断 Transient 是否已经存在。 如果不存在,就使用 add_option() 函数将数据和过期时间添加到 wp_options 表中。 add_option() 的最后一个参数 'no' 非常重要,它告诉 WordPress 不要自动加载这个 Option。 Transient 数据通常不需要在每个页面加载时都加载,所以设置为 'no' 可以提高性能。
  4. else { ... }: 如果 Transient 已经存在,就使用 update_option() 函数更新数据和过期时间。
  5. do_action( 'set_transient_' . $transient, $value, $expiration );: 这是一个 action hook,允许开发者在设置 Transient 之后执行一些操作。

5. delete_transient() 的源码分析

delete_transient() 函数用于删除 Transient 数据。 它的源码如下:

function delete_transient( $transient ) {
    /**
     * Fires before a specific transient is deleted.
     *
     * @since 3.0.0
     *
     * @param string $transient Transient name.
     */
    do_action( 'pre_delete_transient_' . $transient );

    $option_name = '_transient_' . $transient;

    $result = delete_option( $option_name );

    if ( $result ) {
        delete_option( '_transient_timeout_' . $transient );

        /**
         * Fires after a specific transient is deleted.
         *
         * @since 3.0.0
         *
         * @param string $transient Transient name.
         */
        do_action( 'deleted_transient_' . $transient );
    }

    return $result;
}

这段代码的逻辑很简单:

  1. do_action( 'pre_delete_transient_' . $transient );: 这是一个 action hook,允许开发者在删除 Transient 之前执行一些操作。
  2. $option_name = '_transient_' . $transient;: 定义了数据 Option Name。
  3. $result = delete_option( $option_name );: 使用 delete_option() 函数从 wp_options 表中删除数据。
  4. if ( $result ) { ... }: 如果数据删除成功,就删除过期时间。
  5. do_action( 'deleted_transient_' . $transient );: 这是一个 action hook,允许开发者在删除 Transient 之后执行一些操作。

6. wp_options 表:Transient 的存储地

咱们反复提到 wp_options 表,现在就来仔细看看它。 wp_options 表是 WordPress 数据库中非常重要的一个表,用于存储各种各样的配置信息,包括站点标题、描述、主题设置等等。 Transient 数据也存储在这个表中。

wp_options 表的结构如下:

字段名 数据类型 描述
option_id bigint(20) 唯一 ID,自增
option_name varchar(191) Option 的名字,Transient 的 Option Name 格式是 _transient_ 前缀加上 Transient 的名字,过期时间的 Option Name 格式是 _transient_timeout_ 前缀加上 Transient 的名字。
option_value longtext Option 的值,可以是字符串、数字、数组、对象等等。 Transient 数据就存储在这个字段中。
autoload varchar(20) 是否自动加载。 如果设置为 yes,WordPress 会在每个页面加载时都加载这个 Option。 如果设置为 no,则不会自动加载。 Transient 数据通常设置为 no,以提高性能。

7. 总结:Transient 的工作原理

现在,咱们来总结一下 Transient 的工作原理:

  1. 存储: Transient 数据和过期时间都存储在 wp_options 表中,Option Name 有特定的格式。
  2. 获取: get_transient() 函数首先尝试从 wp_options 表中获取数据。 如果数据不存在或者已经过期,就返回 false
  3. 设置: set_transient() 函数将数据和过期时间添加到 wp_options 表中。
  4. 删除: delete_transient() 函数从 wp_options 表中删除数据和过期时间。
  5. 过期: get_transient() 函数在获取数据时会检查过期时间。 如果当前时间已经超过了过期时间,就认为缓存已经过期,会删除缓存并返回 false

8. Transient 的优缺点

优点:

  • 简单易用: WordPress 提供了简单的 get_transient()set_transient()delete_transient() 函数,方便开发者使用。
  • 内置支持: Transient 是 WordPress 内置的缓存机制,不需要安装额外的插件。
  • 基于数据库: Transient 数据存储在数据库中,可以在多个服务器之间共享。

缺点:

  • 性能限制: 由于 Transient 数据存储在数据库中,每次读写都需要访问数据库,性能不如基于内存的缓存(比如 Memcached 或 Redis)。
  • 数据大小限制: wp_options 表的 option_value 字段有大小限制,不适合存储大型数据。
  • 过期时间精度: Transient 的过期时间精度只有秒级,不能精确到毫秒级。

9. 何时使用 Transient?

Transient 适合用于缓存以下类型的数据:

  • 计算成本高的数据: 比如,复杂的数据库查询结果、API 请求结果等。
  • 不需要永久保存的数据: 比如,统计数据、临时数据等。
  • 需要在多个服务器之间共享的数据: 比如,共享的配置信息、会话数据等。

10. Transient 的替代方案

如果 Transient 不能满足你的需求,可以考虑以下替代方案:

  • Object Cache: WordPress 支持 Object Cache,可以使用 Memcached 或 Redis 等基于内存的缓存系统来提高性能。 Object Cache 可以缓存数据库查询结果、对象、页面片段等等。
  • Page Cache: Page Cache 可以缓存整个页面,大大提高页面加载速度。 常用的 Page Cache 插件有 WP Super Cache、W3 Total Cache 等。
  • 自定义缓存: 你也可以自己实现缓存机制,比如使用文件缓存、APC 缓存等。

总结

今天咱们一起深入了解了 WordPress get_transient() 函数的源码, 明白了它是如何利用 wp_options 表和过期时间来实现短暂缓存的。 掌握了 Transient 的工作原理, 就能更好地利用它来提高 WordPress 网站的性能。希望今天的讲解对你有所帮助!下次再见!

发表回复

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