各位观众老爷们,晚上好!我是老码农,今天咱们来聊聊 WordPress 里的一个老朋友,get_option()
函数。这货看起来平平无奇,但却是 WordPress 性能优化的一大利器,它背后默默地操纵着 wp_options
表,并巧妙地运用了对象缓存。今天,咱们就扒开它的底裤,看看它到底是怎么运作的。
一、get_option()
函数:初识庐山真面目
首先,咱们得知道 get_option()
是干嘛的。简单来说,它就是用来从 WordPress 的选项数据库中获取指定选项的值的。这些选项可以包括网站标题、描述、主题设置等等。
函数的基本语法如下:
<?php
/**
* Retrieves an option value based on an option name.
*
* If the option does not exist or does not have a value, then the return will be false.
* This is preferable to employing `isset( get_option( 'nonexistent_option' ) )`,
* as that will call `get_option()` regardless of whether the option is set.
*
* @since 1.5.0
* @since 5.5.0 Added the `$default` parameter.
*
* @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
* @param mixed $default Optional. Default value to return if the option does not exist.
* Default: false.
* @return mixed Value set for the option.
*/
function get_option( $option, $default = false ) {
global $wpdb, $wp_suspend_cache_addition;
$option = trim( $option );
if ( empty( $option ) ) {
return false;
}
// Prevent non-existent options from triggering multiple queries.
$notoptions = wp_cache_get( 'notoptions', 'options' );
if ( isset( $notoptions[ $option ] ) ) {
return $default;
}
$alloptions = wp_load_alloptions();
if ( isset( $alloptions[ $option ] ) ) {
return $alloptions[ $option ];
}
$cache_value = wp_cache_get( $option, 'options' );
if ( false !== $cache_value ) {
/**
* Filters the value of an existing option before it is retrieved from the cache.
*
* The dynamic portion of the hook name, `$option`, refers to the option name.
*
* @since 2.5.0
*
* @param mixed $value The value of the option.
*/
return apply_filters( "pre_option_{$option}", $cache_value );
}
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
// Has to be get_row rather than get_var because of funkiness with database object caching.
if ( is_object( $row ) ) {
$value = $row->option_value;
// Maybe unserialize.
if ( 'yes' === $wp_suspend_cache_addition ) {
$value = maybe_unserialize( $value );
} else {
$value = maybe_unserialize( $value );
wp_cache_add( $option, $value, 'options' );
}
/** This filter is documented in wp-includes/option.php */
return apply_filters( "pre_option_{$option}", $value );
}
// If option is not in alloptions cache.
if ( ! isset( $notoptions[ $option ] ) ) {
$notoptions[ $option ] = true;
wp_cache_set( 'notoptions', $notoptions, 'options' );
}
return $default;
}
参数说明:
$option
:要获取的选项名,字符串类型。$default
:可选参数,如果选项不存在,则返回的默认值。默认为false
。
返回值:
- 如果选项存在,则返回选项的值。
- 如果选项不存在,则返回
$default
参数指定的值,默认为false
。
二、wp_options
表:选项的大本营
WordPress 的选项数据都存储在 wp_options
表中。这个表结构简单粗暴,主要有以下几个字段:
字段名 | 数据类型 | 说明 |
---|---|---|
option_id |
BIGINT(20) |
主键,自增 ID。 |
option_name |
VARCHAR(191) |
选项名,唯一索引。 |
option_value |
LONGTEXT |
选项值,可以存储任何类型的数据,包括字符串、数字、数组、对象等等。WordPress 会自动进行序列化和反序列化。 |
autoload |
VARCHAR(20) |
是否自动加载。如果设置为 yes ,则该选项会在 WordPress 初始化时自动加载到内存中,以便快速访问。如果设置为 no ,则只有在调用 get_option() 时才会从数据库中加载。这个字段对于性能至关重要,后面会详细讲。 |
三、get_option()
的内部运作:抽丝剥茧
现在,咱们深入到 get_option()
的源码中,看看它到底是怎么工作的。
- 参数校验与空选项处理:
$option = trim( $option );
if ( empty( $option ) ) {
return false;
}
首先,函数会对传入的选项名进行去空格处理,如果选项名为空,则直接返回 false
。这属于基本的参数校验。
notoptions
缓存:避免无效查询
$notoptions = wp_cache_get( 'notoptions', 'options' );
if ( isset( $notoptions[ $option ] ) ) {
return $default;
}
这部分代码非常关键。它首先尝试从对象缓存中获取 notoptions
缓存组。notoptions
是一个数组,记录了哪些选项在数据库中不存在。如果我们要获取的选项名存在于 notoptions
中,说明这个选项之前已经被查询过,并且确认不存在,那么函数会直接返回 $default
值,避免重复查询数据库。
这个机制非常聪明,可以有效地减少无效的数据库查询,尤其是在一个页面中多次尝试获取不存在的选项时。
alloptions
缓存:快速访问autoload
选项
$alloptions = wp_load_alloptions();
if ( isset( $alloptions[ $option ] ) ) {
return $alloptions[ $option ];
}
wp_load_alloptions()
函数会从数据库中加载所有 autoload
设置为 yes
的选项,并将它们存储在一个数组中。这个数组会被缓存起来,以便快速访问。
如果我们要获取的选项名存在于 alloptions
数组中,说明这个选项是 autoload
的,并且已经被加载到内存中,那么函数会直接返回选项的值,而无需查询数据库。
autoload
选项的存在,就是为了优化性能。对于一些常用的、需要在每个页面都访问的选项,应该将其 autoload
设置为 yes
,以便快速访问。但是,autoload
选项的数量不宜过多,否则会增加内存占用,反而会降低性能。
- 选项缓存:从对象缓存中直接获取
$cache_value = wp_cache_get( $option, 'options' );
if ( false !== $cache_value ) {
return apply_filters( "pre_option_{$option}", $cache_value );
}
如果选项既不在 notoptions
中,也不在 alloptions
中,那么函数会尝试从对象缓存中获取该选项的值。如果缓存中存在该选项的值,则直接返回,并应用 pre_option_{$option}
过滤器。
WordPress 的对象缓存机制非常强大,可以将数据库查询结果缓存到内存中,以便快速访问。get_option()
函数充分利用了对象缓存,可以有效地减少数据库查询次数,提高网站性能。
- 数据库查询:最后的手段
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
if ( is_object( $row ) ) {
$value = $row->option_value;
$value = maybe_unserialize( $value );
wp_cache_add( $option, $value, 'options' );
return apply_filters( "pre_option_{$option}", $value );
}
如果以上所有方法都失败了,那么 get_option()
函数会执行最后的手段:查询数据库。它会使用 WPDB
类来执行 SQL 查询,从 wp_options
表中获取指定选项的值。
如果查询成功,函数会将选项值进行反序列化(如果需要),然后将其添加到对象缓存中,以便下次快速访问。最后,函数返回选项值,并应用 pre_option_{$option}
过滤器。
- 更新
notoptions
缓存:记录不存在的选项
if ( ! isset( $notoptions[ $option ] ) ) {
$notoptions[ $option ] = true;
wp_cache_set( 'notoptions', $notoptions, 'options' );
}
return $default;
如果数据库查询失败,说明该选项在数据库中不存在。为了避免下次重复查询,函数会将该选项名添加到 notoptions
缓存中。
四、对象缓存:性能优化的基石
get_option()
函数的性能优化,很大程度上依赖于 WordPress 的对象缓存机制。对象缓存可以将数据库查询结果缓存到内存中,以便快速访问,从而减少数据库查询次数,提高网站性能。
WordPress 提供了多种对象缓存的实现方式,包括:
- Transient API: 简单易用,适用于存储临时数据。
- WP_Object_Cache 类: 提供更高级的缓存控制,适用于存储复杂数据。
- 外部缓存: 使用 Memcached、Redis 等外部缓存系统,可以提供更高的性能和可扩展性。
get_option()
函数主要使用 WP_Object_Cache
类来进行对象缓存。它会将选项值存储在 options
缓存组中,并使用选项名作为缓存键。
五、autoload
选项:权衡利弊
autoload
选项是一个双刃剑。它可以提高常用选项的访问速度,但也会增加内存占用。
- 优点: 减少数据库查询次数,提高网站性能。
- 缺点: 增加内存占用,可能导致性能下降。
因此,在使用 autoload
选项时,需要权衡利弊,只将常用的、需要在每个页面都访问的选项设置为 yes
。
六、pre_option_{$option}
过滤器:灵活扩展
get_option()
函数在返回选项值之前,会应用 pre_option_{$option}
过滤器。这个过滤器允许开发者修改选项值,或者从其他来源获取选项值。
例如,我们可以使用 pre_option_{$option}
过滤器来实现多站点共享选项:
<?php
add_filter( 'pre_option_my_option', 'my_get_shared_option' );
function my_get_shared_option( $value ) {
if ( is_multisite() && ! get_current_blog_id() ) {
switch_to_blog( 1 ); // Switch to the main site.
$value = get_option( 'my_option' );
restore_current_blog(); // Switch back to the current site.
}
return $value;
}
这段代码会在多站点环境下,如果当前站点不是主站点,则从主站点获取 my_option
选项的值。
七、总结:get_option()
的智慧
get_option()
函数看似简单,但却蕴含着 WordPress 性能优化的智慧。它通过以下手段来提高性能:
- 参数校验: 避免无效操作。
notoptions
缓存: 避免无效查询。alloptions
缓存: 快速访问autoload
选项。- 对象缓存: 减少数据库查询次数。
autoload
选项: 权衡利弊。pre_option_{$option}
过滤器: 灵活扩展。
掌握 get_option()
函数的运作机制,可以帮助我们更好地理解 WordPress 的性能优化策略,并编写更高效的代码。
希望今天的讲座对大家有所帮助。下次再见!