各位观众老爷们,大家好!今天咱们来聊聊WordPress里一个很实用,但又容易被忽略的小家伙:get_transient()
。 别看它名字平平无奇,在优化网站性能方面,它可是个隐藏的大佬。 今天我就扒开它的源码,让大家彻底明白它到底是怎么玩的,怎么用它来让你的网站飞起来。
开场白:为啥需要缓存?
想象一下,每次有人访问你的网站,服务器都要辛辛苦苦地从数据库里捞数据,然后拼装成网页,是不是太累了? 如果访问量一大,服务器就容易卡壳,用户体验直线下降。 这时候,缓存就闪亮登场了。
缓存就像是你家里的冰箱,把常用的东西(比如数据库查询结果)提前放进去,下次要用的时候,直接从冰箱里拿,省时省力。 WordPress里的Transient API就是用来干这个的,而get_transient()
就是从这个“冰箱”里拿东西的钥匙。
get_transient()
:拿东西的钥匙
get_transient()
函数的作用很简单,就是根据你给的键名(key),从Transient缓存里取出对应的值。 如果缓存里没有这个键,或者缓存已经过期了,它就返回 false
。
<?php
/**
* Retrieve the value of a transient.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return mixed Value of transient. If does not exist, returns false.
*/
function get_transient( string $transient ) {
return get_site_transient( $transient );
}
可以看到,get_transient()
本身只是一个简单的壳,它直接调用了 get_site_transient()
。 所以,要深入理解,我们得看看 get_site_transient()
到底做了什么。
get_site_transient()
:深入虎穴
get_site_transient()
函数才是真正干活的家伙。 它负责从数据库里读取Transient数据,并检查是否过期。
<?php
/**
* Get the value of a site transient.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return mixed Value of transient. If does not exist, returns false.
*/
function get_site_transient( string $transient ) {
global $wpdb;
$transient = sanitize_key( $transient );
$transient_option = '_site_transient_' . $transient;
/**
* Filters the value of an existing site transient.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* Passing a non-null value to the filter will effectively short-circuit get_site_transient(),
* returning the passed value instead.
*
* @since 2.9.0
*
* @param mixed $pre_transient The default value to return if the transient does not exist.
* Any value other than null will short-circuit the retrieval
* and return the passed value.
* @param string $transient Transient name.
*/
$pre = apply_filters( "pre_site_transient_{$transient}", null, $transient );
if ( null !== $pre ) {
return $pre;
}
$value = get_option( $transient_option );
if ( false === $value ) {
return false;
}
$expiration = get_option( '_site_transient_timeout_' . $transient );
if ( false !== $expiration && time() > $expiration ) {
delete_site_transient( $transient );
return false;
}
/**
* Filters an existing site transient's value.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 2.9.0
*
* @param mixed $value Value of transient.
* @param string $transient Transient name.
*/
return apply_filters( "site_transient_{$transient}", $value, $transient );
}
让我们一步步拆解:
-
安全第一:
sanitize_key()
$transient = sanitize_key( $transient );
首先,它会对你传入的键名(
$transient
)进行安全处理,使用sanitize_key()
函数,确保键名是合法的,防止SQL注入之类的安全问题。sanitize_key()
函数会将键名转换为小写,并移除所有非字母、数字、下划线、短横线和点号的字符。 -
构建Option名:
_site_transient_
前缀$transient_option = '_site_transient_' . $transient;
接下来,它会在你的键名前面加上
_site_transient_
前缀,生成一个Option名($transient_option
)。 这个Option名就是用来在数据库里存储实际Transient数据的地方。 例如,如果你传入的键名是my_data
,那么生成的Option名就是_site_transient_my_data
。 -
过滤器:
pre_site_transient_{$transient}
$pre = apply_filters( "pre_site_transient_{$transient}", null, $transient ); if ( null !== $pre ) { return $pre; }
这里用到了一个过滤器
pre_site_transient_{$transient}
。 这个过滤器允许你提前修改或者直接返回Transient的值,而不用去数据库里查。 如果你给这个过滤器设置了一个非null
的返回值,那么get_site_transient()
函数会直接返回你设置的值,不再继续执行后面的代码。 这在某些特殊情况下非常有用,比如你想手动控制Transient的返回值。 -
读取Option:
get_option()
$value = get_option( $transient_option ); if ( false === $value ) { return false; }
现在,它终于要从数据库里读取数据了。 它使用
get_option()
函数,根据之前生成的Option名($transient_option
),从wp_options
表里读取对应的Option值。 如果数据库里没有这个Option,get_option()
会返回false
,get_site_transient()
也会跟着返回false
,表示缓存未命中。 -
检查过期时间:
_site_transient_timeout_
前缀$expiration = get_option( '_site_transient_timeout_' . $transient ); if ( false !== $expiration && time() > $expiration ) { delete_site_transient( $transient ); return false; }
重点来了! 这里要检查缓存是否过期。 它会先根据键名,加上
_site_transient_timeout_
前缀,生成一个Timeout Option名,然后使用get_option()
函数读取对应的过期时间。 例如,如果你的键名是my_data
,那么生成的Timeout Option名就是_site_transient_timeout_my_data
。如果找到了过期时间,并且当前时间已经超过了过期时间,那么它会调用
delete_site_transient()
函数删除这个Transient,并返回false
,表示缓存已过期。 -
过滤器:
site_transient_{$transient}
return apply_filters( "site_transient_{$transient}", $value, $transient );
最后,它又使用了一个过滤器
site_transient_{$transient}
。 这个过滤器允许你在返回Transient值之前,对它进行最后的修改。 你可以通过这个过滤器,对Transient值进行一些处理,然后再返回给调用者。
set_transient()
和 delete_transient()
:设置和删除
光会拿东西还不行,还得会放东西和扔东西。 set_transient()
和 delete_transient()
函数就是用来干这个的。
-
set_transient()
:往冰箱里放东西set_transient()
函数用来设置一个Transient缓存。 它接受三个参数:键名($transient
)、值($value
)和过期时间($expiration
)。<?php /** * Set/update the value of a transient. * * You must use underscores for the name of the transient. * * @since 2.8.0 * * @param string $transient Transient name. Expected to not be SQL-escaped. Must be * 40 characters or less. * @param mixed $value Transient value. Must be serializable if non-scalar. * Expected to not be SQL-escaped. * @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration). * @return bool False if value was not set and true if value was set. */ function set_transient( string $transient, mixed $value, int $expiration = 0 ) { return set_site_transient( $transient, $value, $expiration ); }
同样,
set_transient()
也是一个壳,它调用了set_site_transient()
。 -
delete_transient()
:把冰箱里的东西扔掉delete_transient()
函数用来删除一个Transient缓存。 它接受一个参数:键名($transient
)。<?php /** * Delete a transient. * * @since 2.8.0 * * @param string $transient Transient name. Expected to not be SQL-escaped. * @return bool True if the transient was successfully deleted, false otherwise. */ function delete_transient( string $transient ) { return delete_site_transient( $transient ); }
delete_transient()
也是一个壳,它调用了delete_site_transient()
。
set_site_transient()
和 delete_site_transient()
:幕后英雄
这两个函数才是真正负责设置和删除Transient缓存的。 它们的实现原理和 get_site_transient()
类似,也是通过操作 wp_options
表来实现的。
-
set_site_transient()
:设置Transient<?php /** * Set the value of a site transient. * * @since 2.8.0 * * @param string $transient Transient name. Expected to not be SQL-escaped. Must be * 40 characters or less. * @param mixed $value Transient value. Must be serializable if non-scalar. * Expected to not be SQL-escaped. * @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration). * @return bool False if value was not set and true if value was set. */ function set_site_transient( string $transient, mixed $value, int $expiration = 0 ) { global $wpdb; $transient = sanitize_key( $transient ); /** * Filters the value of an existing site transient before it is set. * * The dynamic portion of the hook name, `$transient`, refers to the transient name. * * @since 2.9.0 * * @param mixed $value New value of transient. * @param string $transient Transient name. * @param int $expiration Time until expiration in seconds. */ $value = apply_filters( "pre_set_site_transient_{$transient}", $value, $transient, $expiration ); if ( is_serialized( $value ) ) { $value = wp_unslash( $value ); } $transient_timeout = '_site_transient_timeout_' . $transient; $transient = '_site_transient_' . $transient; if ( false === get_option( $transient ) ) { $autoload = 'yes'; if ( $expiration ) { $autoload = 'no'; add_option( $transient_timeout, time() + $expiration, '', $autoload ); } $result = add_option( $transient, $value, '', $autoload ); if ( $result ) { /** * Fires after the value of a site transient has been set. * * The dynamic portion of the hook name, `$transient`, refers to the transient name. * * @since 2.9.0 * * @param mixed $value Transient value. * @param string $transient Transient name. * @param int $expiration Time until expiration in seconds. */ do_action( "set_site_transient_{$transient}", $value, $transient, $expiration ); return true; } return false; } else { if ( $expiration ) { update_option( $transient_timeout, time() + $expiration ); } else { delete_option( $transient_timeout ); } $result = update_option( $transient, $value ); if ( $result ) { /** * Fires after the value of an existing site transient has been updated. * * The dynamic portion of the hook name, `$transient`, refers to the transient name. * * @since 2.9.0 * * @param mixed $value Transient value. * @param string $transient Transient name. * @param int $expiration Time until expiration in seconds. */ do_action( "set_site_transient_{$transient}", $value, $transient, $expiration ); return true; } return false; } }
- 安全处理:
sanitize_key()
首先,会对键名进行安全处理,防止SQL注入。 - 过滤器:
pre_set_site_transient_{$transient}
允许在设置Transient之前,修改Transient的值。 - 处理序列化数据
如果是序列化数据,会进行反斜杠处理。 - 构建Option名:
_site_transient_timeout_
和_site_transient_
分别构建存储过期时间和Transient值的Option名。 - 判断Option是否存在
如果Option不存在,则使用add_option()
添加Option。 如果Option存在,则使用update_option()
更新Option。 - 设置过期时间
如果设置了过期时间,则将过期时间存储在_site_transient_timeout_
Option中。 - 过滤器:
set_site_transient_{$transient}
在设置Transient之后,触发一个Action,允许执行一些额外的操作。
- 安全处理:
-
delete_site_transient()
:删除Transient<?php /** * Delete a site transient. * * @since 2.8.0 * * @param string $transient Transient name. Expected to not be SQL-escaped. * @return bool True if the transient was successfully deleted, false otherwise. */ function delete_site_transient( string $transient ) { $transient = sanitize_key( $transient ); /** * Fires before a site transient is deleted. * * The dynamic portion of the hook name, `$transient`, refers to the transient name. * * @since 2.9.0 * * @param string $transient Transient name. */ do_action( "delete_site_transient_{$transient}", $transient ); $option_timeout = '_site_transient_timeout_' . $transient; $option = '_site_transient_' . $transient; $result = delete_option( $option ); if ( $result ) { delete_option( $option_timeout ); /** * Fires after a site transient is deleted. * * The dynamic portion of the hook name, `$transient`, refers to the transient name. * * @since 2.9.0 * * @param string $transient Transient name. */ do_action( "deleted_site_transient_{$transient}", $transient ); return true; } return false; }
- 安全处理:
sanitize_key()
首先,会对键名进行安全处理,防止SQL注入。 - 过滤器:
delete_site_transient_{$transient}
在删除Transient之前,触发一个Action,允许执行一些额外的操作。 - 构建Option名:
_site_transient_timeout_
和_site_transient_
分别构建存储过期时间和Transient值的Option名。 - 删除Option:
delete_option()
分别删除存储过期时间和Transient值的Option。 - 过滤器:
deleted_site_transient_{$transient}
在删除Transient之后,触发一个Action,允许执行一些额外的操作。
- 安全处理:
Transient的存储方式
Transient数据实际上是存储在 wp_options
表里的。 每个Transient都对应两条记录:
- 一条记录存储Transient的值,Option名以
_site_transient_
开头。 - 一条记录存储Transient的过期时间,Option名以
_site_transient_timeout_
开头。
Option Name | Option Value |
---|---|
_site_transient_my_data |
a:1:{s:5:"value";i:123;} (序列化的数据) |
_site_transient_timeout_my_data |
1678886400 (Unix时间戳) |
使用场景举例
假设你要缓存一个需要耗时计算的结果:
<?php
$data = get_transient( 'my_complex_data' );
if ( false === $data ) {
// 缓存未命中,需要重新计算
$data = calculate_complex_data(); // 假设这个函数很耗时
// 将结果缓存起来,有效期1小时
set_transient( 'my_complex_data', $data, 3600 );
}
// 使用缓存的数据
echo $data;
注意事项
- 键名长度限制: Transient的键名长度不能超过40个字符。
- 数据类型: Transient可以存储各种类型的数据,包括字符串、数字、数组、对象等。 但是,非标量数据需要序列化才能存储。
- 过期时间: 合理设置过期时间非常重要。 如果过期时间太短,缓存就起不到作用。 如果过期时间太长,缓存的数据可能就过时了。
- Autoload: Transient的Autoload选项默认是
yes
,表示在WordPress加载时自动加载。 如果你的Transient数据量很大,建议将Autoload设置为no
,以减少内存消耗。
总结
get_transient()
函数是 WordPress Transient API 的核心函数之一,它通过操作 wp_options
表,实现了键值对缓存和过期时间的功能。 合理使用Transient API,可以有效提高网站的性能和用户体验。
希望今天的讲座对大家有所帮助! 以后再遇到性能问题,记得想起 get_transient()
这个小可爱,它能让你的网站跑得更快,飞得更高!