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

各位听众,早上好/下午好/晚上好! 今天咱们来聊聊 WordPress 的“小秘密”——get_transient() 函数。别看它名字平平无奇,实际上它可是 WordPress 缓存机制中的一位重要成员。它能让你在数据库里“偷偷”存放一些临时数据,就像在冰箱里放个冰淇淋,过会儿拿出来吃,省得每次都现做。

咱们今天要深入它的源码,看看它到底是怎么运作的,又是如何跟 wp_options 表,以及那个让人又爱又恨的“过期时间”打交道的。准备好了吗? Let’s dive in!

1. Transient 究竟是啥?

首先,咱们得明白什么是 Transient。简单来说,Transient 就是一个临时的缓存数据,它有一个过期时间,过了这个时间,数据就会自动失效。想象一下,你用积分换购了一张电影票,这张票在有效期内有效,过了期就作废了。Transient 的作用就类似这样。

为什么要用 Transient 呢? 主要是为了减轻数据库的压力,提高网站的性能。 比如,你要显示一个热门文章列表,每次都去数据库里查询,效率肯定不高。但如果把热门文章列表缓存成一个 Transient,隔一段时间更新一次,就能大大提高速度。

2. get_transient() 函数:寻宝之旅的开始

get_transient() 函数是用来获取 Transient 值的。 它的基本用法是:

$value = get_transient( 'my_transient_key' );

if ( false === $value ) {
  // Transient 不存在或者已过期,重新计算值
  $value = calculate_expensive_value();

  // 设置 Transient,有效期为 1 小时 (3600 秒)
  set_transient( 'my_transient_key', $value, 3600 );
}

// 现在 $value 就是我们要用的值了
echo $value;

这段代码做了什么呢?

  • 首先,它尝试从 Transient 里获取 my_transient_key 对应的值。
  • 如果 get_transient() 返回 false,说明 Transient 不存在或者已经过期了,需要重新计算值。
  • 重新计算后,用 set_transient() 函数设置 Transient,并设置过期时间为 1 小时。
  • 最后,就可以使用 Transient 的值了。

那么,get_transient() 到底是怎么找到这个值的呢? 让我们一起深入源码看看。

3. get_transient() 源码剖析:深入 wp-includes/option.php

打开 wp-includes/option.php 文件,找到 get_transient() 函数。 它的源码大致如下:

function get_transient( $transient ) {
    /**
     * Fires before a cached transient is retrieved.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 2.8.0
     *
     * @param string $transient Transient name.
     */
    do_action( 'pre_get_transient_' . $transient );

    $pre = apply_filters( 'pre_transient_' . $transient, false );
    if ( false !== $pre ) {
        return $pre;
    }

    $transient_option = _transient_key( $transient );
    $transient_timeout = _transient_timeout_key( $transient );

    $timeout = get_option( $transient_timeout );

    if ( false !== $timeout && time() > intval( $timeout ) ) {
        delete_transient( $transient );
        return false;
    }

    $value = get_option( $transient_option );

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

哇,看起来有点复杂,别怕,咱们一步一步来分析。

  • Hook 机制:do_action()apply_filters()

    首先,我们看到 do_action( 'pre_get_transient_' . $transient );apply_filters( 'pre_transient_' . $transient, false ); 这两行代码。 这是 WordPress 的 Hook 机制,允许我们在 Transient 被获取之前,执行一些自定义的操作。

    do_action() 允许我们执行一些操作,但不返回任何值。 比如,我们可以在 Transient 被获取之前,记录一条日志。

    apply_filters() 允许我们修改 Transient 的值。 如果 apply_filters() 返回的值不是 false,那么 get_transient() 函数就会直接返回这个值,而不会继续往下执行。 这提供了一种非常灵活的方式来控制 Transient 的获取过程。

  • 生成 Option Key:_transient_key()_transient_timeout_key()

    接下来,我们看到:

    $transient_option = _transient_key( $transient );
    $transient_timeout = _transient_timeout_key( $transient );

    这两个函数分别生成了 Transient 的 Option Key 和 Timeout Key。 它们的作用是把 Transient 的名字转换成在 wp_options 表中存储的 key。

    让我们看看这两个函数的源码:

    function _transient_key( $transient ) {
      return '_transient_' . $transient;
    }
    
    function _transient_timeout_key( $transient ) {
      return '_transient_timeout_' . $transient;
    }

    很简单,它们只是在 Transient 的名字前面加上了 _transient__transient_timeout_ 前缀。 比如,如果 Transient 的名字是 my_transient_key,那么 Option Key 就是 _transient_my_transient_key,Timeout Key 就是 _transient_timeout_my_transient_key

  • 获取 Timeout 值:get_option()

    然后,我们看到:

    $timeout = get_option( $transient_timeout );

    这里使用 get_option() 函数从 wp_options 表中获取 Timeout 值。 get_option() 是 WordPress 提供的一个非常重要的函数,它可以从 wp_options 表中获取 Option 的值。

    wp_options 表是 WordPress 用来存储各种设置和数据的表格。 它有两个重要的字段:option_nameoption_valueoption_name 存储 Option 的名字,option_value 存储 Option 的值。

    所以,get_option( $transient_timeout ) 实际上就是从 wp_options 表中查找 option_name 等于 $transient_timeout 的记录,并返回对应的 option_value

  • 检查是否过期:time() > intval( $timeout )

    接下来,我们看到:

    if ( false !== $timeout && time() > intval( $timeout ) ) {
      delete_transient( $transient );
      return false;
    }

    这里检查 Transient 是否已经过期。 首先,判断 $timeout 是否为 false。 如果 $timeoutfalse,说明这个 Transient 还没有设置 Timeout 值,也就是没有设置过期时间,那么就认为它没有过期。

    如果 $timeout 不为 false,那么就判断当前时间是否大于 Timeout 值。 如果当前时间大于 Timeout 值,说明 Transient 已经过期了,需要调用 delete_transient() 函数删除 Transient,并返回 false

    time() 函数返回当前的时间戳,intval() 函数把 Timeout 值转换成整数。

  • 获取 Transient 值:get_option()

    如果 Transient 没有过期,那么就执行:

    $value = get_option( $transient_option );

    这里再次使用 get_option() 函数从 wp_options 表中获取 Transient 的值。 这次获取的是 Option Key 对应的值,也就是 Transient 的实际数据。

  • Hook 机制:apply_filters()

    最后,我们看到:

    return apply_filters( 'transient_' . $transient, $value, $transient );

    这里又使用了一次 apply_filters() 函数。 这次的 Hook 是 transient_ + Transient 的名字。 这个 Hook 允许我们在 Transient 的值被返回之前,修改它的值。

    这又提供了一种非常灵活的方式来控制 Transient 的返回值。

4. set_transient() 函数:把冰淇淋放进冰箱

现在,我们已经知道了 get_transient() 函数是如何获取 Transient 的值的。 接下来,让我们看看 set_transient() 函数是如何设置 Transient 的值的。

set_transient() 函数的基本用法是:

set_transient( 'my_transient_key', $value, 3600 );

这段代码做了什么呢?

  • 它把 $value 存储到 my_transient_key 对应的 Transient 中。
  • 设置过期时间为 3600 秒,也就是 1 小时。

让我们深入源码看看 set_transient() 函数是如何实现的。

打开 wp-includes/option.php 文件,找到 set_transient() 函数。 它的源码大致如下:

function set_transient( $transient, $value, $expiration = 0 ) {
    /**
     * Fires before a cached transient is set.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 2.8.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 );

    $transient_timeout = _transient_timeout_key( $transient );
    $transient = _transient_key( $transient );

    if ( false === get_option( $transient ) ) {
        $autoload = 'yes';
        if ( is_int( $expiration ) && $expiration ) {
            $autoload = 'no';
            add_option( $transient_timeout, time() + $expiration, '', $autoload );
        }
        $result = add_option( $transient, $value, '', $autoload );
        if ( $autoload == 'no' ) {
            wp_cache_add( $transient_timeout, time() + $expiration, 'options', $expiration );
        }
    } else {
        if ( is_int( $expiration ) && $expiration ) {
            update_option( $transient_timeout, time() + $expiration );
        } else {
            delete_option( $transient_timeout );
        }
        $result = update_option( $transient, $value );
    }

    if ( $result ) {
        wp_cache_set( $transient, $value, 'options', $expiration );
    }

    /**
     * Fires after a transient is set.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 2.8.0
     *
     * @param string $transient  Transient name.
     * @param mixed  $value      Transient value.
     * @param int    $expiration Time until expiration in seconds.
     */
    do_action( 'setted_transient_' . $transient, $value, $expiration );

    return $result;
}

同样,咱们一步一步来分析。

  • Hook 机制:do_action()

    首先,我们看到 do_action( 'set_transient_' . $transient, $value, $expiration ); 这行代码。 这是 WordPress 的 Hook 机制,允许我们在 Transient 被设置之前,执行一些自定义的操作。

  • 生成 Option Key:_transient_key()_transient_timeout_key()

    接下来,我们看到:

    $transient_timeout = _transient_timeout_key( $transient );
    $transient = _transient_key( $transient );

    这两个函数的作用和 get_transient() 函数里的一样,都是用来生成 Transient 的 Option Key 和 Timeout Key。

  • 判断 Transient 是否存在:get_option()

    然后,我们看到:

    if ( false === get_option( $transient ) ) {
      // Transient 不存在
    } else {
      // Transient 存在
    }

    这里使用 get_option() 函数判断 Transient 是否已经存在。 如果 get_option() 返回 false,说明 Transient 不存在,需要使用 add_option() 函数添加 Transient。 否则,说明 Transient 已经存在,需要使用 update_option() 函数更新 Transient。

  • 添加 Transient:add_option()

    如果 Transient 不存在,那么就执行:

    $autoload = 'yes';
    if ( is_int( $expiration ) && $expiration ) {
      $autoload = 'no';
      add_option( $transient_timeout, time() + $expiration, '', $autoload );
    }
    $result = add_option( $transient, $value, '', $autoload );
    if ( $autoload == 'no' ) {
      wp_cache_add( $transient_timeout, time() + $expiration, 'options', $expiration );
    }

    这里使用 add_option() 函数添加 Transient。

    add_option() 函数的作用是在 wp_options 表中添加一条新的记录。 它有四个参数:

    • $option_name:Option 的名字。
    • $option_value:Option 的值。
    • $deprecated:已弃用的参数,可以忽略。
    • $autoload:是否自动加载。

    $autoload 参数控制着这个 Option 是否在 WordPress 启动时自动加载。 如果 $autoload 设置为 'yes',那么这个 Option 会在 WordPress 启动时自动加载,这会提高性能。 但是,如果 Option 的值很大,或者很少使用,那么就不应该自动加载,应该把 $autoload 设置为 'no'

    在这里,我们首先判断是否设置了过期时间。 如果设置了过期时间,就把 $autoload 设置为 'no',并使用 add_option() 函数添加 Timeout 值。 然后,使用 add_option() 函数添加 Transient 的值。

    如果 $autoloadno,则使用 wp_cache_add 将超时时间添加到对象缓存中,有效期与 transient 相同。

  • 更新 Transient:update_option()

    如果 Transient 已经存在,那么就执行:

    if ( is_int( $expiration ) && $expiration ) {
      update_option( $transient_timeout, time() + $expiration );
    } else {
      delete_option( $transient_timeout );
    }
    $result = update_option( $transient, $value );

    这里使用 update_option() 函数更新 Transient。

    update_option() 函数的作用是更新 wp_options 表中已有的记录。 它有两个参数:

    • $option_name:Option 的名字。
    • $option_value:Option 的值。

    在这里,我们首先判断是否设置了过期时间。 如果设置了过期时间,就使用 update_option() 函数更新 Timeout 值。 否则,就使用 delete_option() 删除 timeout option。 然后,使用 update_option() 函数更新 Transient 的值。

  • 对象缓存:wp_cache_set()

    最后,我们看到:

    if ( $result ) {
      wp_cache_set( $transient, $value, 'options', $expiration );
    }

    如果 add_option()update_option() 函数执行成功,那么就使用 wp_cache_set() 函数把 Transient 的值添加到对象缓存中。

    对象缓存是 WordPress 提供的一种更高级的缓存机制。 它可以把数据存储到内存中,从而大大提高性能。

    wp_cache_set() 函数的作用是把数据存储到对象缓存中。 它有四个参数:

    • $key:缓存的 key。
    • $data:缓存的数据。
    • $group:缓存的组。
    • $expire:过期时间。

    在这里,我们把 Transient 的名字作为缓存的 key,把 Transient 的值作为缓存的数据,把 'options' 作为缓存的组,把过期时间作为缓存的过期时间。

  • Hook 机制:do_action()

    最后,我们看到 do_action( 'setted_transient_' . $transient, $value, $expiration ); 这行代码。 这是 WordPress 的 Hook 机制,允许我们在 Transient 被设置之后,执行一些自定义的操作。

5. delete_transient() 函数:冰淇淋过期了,扔掉!

delete_transient() 函数是用来删除 Transient 的。 它的基本用法是:

delete_transient( 'my_transient_key' );

这段代码会删除 my_transient_key 对应的 Transient。

让我们深入源码看看 delete_transient() 函数是如何实现的。

打开 wp-includes/option.php 文件,找到 delete_transient() 函数。 它的源码大致如下:

function delete_transient( $transient ) {
    /**
     * Fires before a transient is deleted.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 2.8.0
     *
     * @param string $transient Transient name.
     */
    do_action( 'delete_transient_' . $transient );

    $transient_timeout = _transient_timeout_key( $transient );
    $transient = _transient_key( $transient );

    $result = delete_option( $transient );

    if ( $result ) {
        delete_option( $transient_timeout );
        wp_cache_delete( $transient, 'options' );
    }

    /**
     * Fires after a transient is deleted.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 2.8.0
     *
     * @param string $transient Transient name.
     */
    do_action( 'deleted_transient_' . $transient );

    return $result;
}

这次的源码比较简单,我们直接分析。

  • Hook 机制:do_action()

    首先,我们看到 do_action( 'delete_transient_' . $transient ); 这行代码。 这是 WordPress 的 Hook 机制,允许我们在 Transient 被删除之前,执行一些自定义的操作。

  • 生成 Option Key:_transient_key()_transient_timeout_key()

    接下来,我们看到:

    $transient_timeout = _transient_timeout_key( $transient );
    $transient = _transient_key( $transient );

    这两个函数的作用和 get_transient() 函数里的一样,都是用来生成 Transient 的 Option Key 和 Timeout Key。

  • 删除 Transient:delete_option()

    然后,我们看到:

    $result = delete_option( $transient );

    这里使用 delete_option() 函数删除 Transient。

    delete_option() 函数的作用是从 wp_options 表中删除一条记录。 它的参数是 Option 的名字。

  • 删除 Timeout 值:delete_option()

    接下来,我们看到:

    if ( $result ) {
      delete_option( $transient_timeout );
      wp_cache_delete( $transient, 'options' );
    }

    如果 delete_option( $transient ) 函数执行成功,那么就使用 delete_option() 函数删除 Timeout 值,并使用 wp_cache_delete() 函数从对象缓存中删除 Transient。

  • Hook 机制:do_action()

    最后,我们看到 do_action( 'deleted_transient_' . $transient ); 这行代码。 这是 WordPress 的 Hook 机制,允许我们在 Transient 被删除之后,执行一些自定义的操作。

6. Transient 与 wp_options 表:幕后英雄

现在,我们已经了解了 get_transient()set_transient()delete_transient() 函数的源码。 我们可以看到,这三个函数都与 wp_options 表密切相关。

wp_options 表是 WordPress 用来存储各种设置和数据的表格。 Transient 实际上就是把数据存储到 wp_options 表中,并设置一个过期时间。

wp_options 表有两个重要的字段:option_nameoption_valueoption_name 存储 Option 的名字,option_value 存储 Option 的值。

当我们使用 set_transient() 函数设置一个 Transient 时,实际上是向 wp_options 表中添加了两条记录:

  • 一条记录存储 Transient 的值,option_name_transient_ + Transient 的名字,option_value 是 Transient 的值。
  • 一条记录存储 Transient 的过期时间,option_name_transient_timeout_ + Transient 的名字,option_value 是过期时间的时间戳。

当我们使用 get_transient() 函数获取一个 Transient 的值时,实际上是从 wp_options 表中查找 option_name 等于 _transient_ + Transient 的名字的记录,并返回对应的 option_value。 同时,还会检查 _transient_timeout_ + Transient 的名字对应的记录是否存在,以及是否已经过期。

当我们使用 delete_transient() 函数删除一个 Transient 时,实际上是从 wp_options 表中删除 option_name 等于 _transient_ + Transient 的名字和 _transient_timeout_ + Transient 的名字的两条记录。

可以用表格总结一下:

函数 操作 wp_options 表记录
set_transient() 设置 Transient 值和过期时间 添加/更新两条记录:_transient_{transient_name} (值) 和 _transient_timeout_{transient_name} (过期时间戳)
get_transient() 获取 Transient 值,检查是否过期 根据 _transient_{transient_name} 获取值,根据 _transient_timeout_{transient_name} 检查是否过期,过期则删除记录
delete_transient() 删除 Transient 值和过期时间 删除两条记录:_transient_{transient_name}_transient_timeout_{transient_name}

7. 总结:Transient 的力量

通过今天的讲座,我们深入了解了 WordPress 的 get_transient() 函数,以及它与 wp_options 表和过期时间的关系。 我们可以看到,Transient 是一种非常强大的缓存机制,它可以帮助我们提高 WordPress 网站的性能。

使用 Transient 的好处包括:

  • 减轻数据库压力:减少对数据库的查询次数。
  • 提高网站性能:更快地加载页面。
  • 灵活性:可以设置过期时间,自动失效。

但是,使用 Transient 也需要注意一些问题:

  • 不要存储过大的数据wp_options 表不适合存储过大的数据。
  • 合理设置过期时间:过期时间太短,缓存效果不明显;过期时间太长,数据可能过时。
  • 注意 Transient 的命名:Transient 的名字应该具有唯一性,避免冲突。

希望今天的讲座对大家有所帮助。 感谢各位的聆听!下次再见!

发表回复

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