详解 WordPress `wp_cache_init()` 函数的源码:如何初始化对象缓存,并加载 `advanced-cache.php`。

各位观众老爷们,晚上好!我是你们的老朋友,今天咱们来聊聊 WordPress 缓存机制里一个神秘但关键的家伙——wp_cache_init() 函数。别看名字平平无奇,它可是 WordPress 对象缓存的启动器,负责初始化对象缓存,并且加载传说中的 advanced-cache.php

准备好了吗?咱们这就开车,深入源码,扒一扒它的底裤!

一、wp_cache_init() 函数:对象缓存的幕后推手

首先,让我们来看看 wp_cache_init() 函数的真面目。这函数定义在 wp-includes/cache.php 文件里。

function wp_cache_init() {
    global $wp_object_cache;

    /**
     * Fires after object cache is initialized.
     *
     * @since 2.6.0
     */
    do_action( 'init', 'object' );

    if ( ! WP_CACHE ) {
        $wp_object_cache = new WP_Object_Cache();
        return;
    }

    /**
     * Allows replacement of the default WordPress object cache.
     *
     * The WordPress object cache is used to store data that may be resource
     * intensive to retrieve. The cache is used to improve performance by
     * storing data in memory.
     *
     * This action allows plugins to replace the default WordPress object cache
     * with a custom object cache.
     *
     * @since 2.6.0
     *
     * @param string|object $wp_object_cache The global object cache object.
     */
    do_action( 'start_object_cache', $wp_object_cache ); // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable

    $wp_cache_file_path = WP_CONTENT_DIR . '/advanced-cache.php';

    if ( file_exists( $wp_cache_file_path ) ) {
        require_once $wp_cache_file_path;
    }

    // If a WP_Object_Cache class isn't defined, load the default one.
    if ( ! is_object( $wp_object_cache ) || ! ( $wp_object_cache instanceof WP_Object_Cache ) ) {
        require_once ABSPATH . 'wp-includes/cache.php';
        $wp_object_cache = new WP_Object_Cache();
    }

    add_action( 'shutdown', 'wp_cache_close' );
}

简单来说,wp_cache_init() 的主要任务有以下几点:

  1. 触发 init 钩子: do_action( 'init', 'object' ); 允许插件在对象缓存初始化之后执行一些操作。这个钩子传递了 'object' 作为参数,可以用于区分其他 init 钩子的用途。

  2. 检查 WP_CACHE 常量: if ( ! WP_CACHE ) 检查 WP_CACHE 常量是否定义为 trueWP_CACHE 常量定义在 wp-config.php 文件中,用于启用或禁用对象缓存。 如果 WP_CACHE 没有定义或者定义为 false,则使用 WordPress 自带的简单对象缓存 WP_Object_Cache,并直接返回。

  3. 触发 start_object_cache 钩子: 如果 WP_CACHEtrue,则触发 start_object_cache 钩子,允许插件替换 WordPress 默认的对象缓存。

  4. 加载 advanced-cache.php: 这是最关键的一步。$wp_cache_file_path = WP_CONTENT_DIR . '/advanced-cache.php'; 定义了 advanced-cache.php 文件的路径。然后,if ( file_exists( $wp_cache_file_path ) ) { require_once $wp_cache_file_path; } 检查 advanced-cache.php 文件是否存在,如果存在,则加载它。 这个文件通常包含着对 WordPress 对象缓存的自定义实现,比如使用 Memcached 或 Redis 等缓存系统。

  5. 确保 WP_Object_Cache 对象存在: if ( ! is_object( $wp_object_cache ) || ! ( $wp_object_cache instanceof WP_Object_Cache ) ) 检查 $wp_object_cache 全局变量是否是一个 WP_Object_Cache 类的实例。 如果不是,则加载 WordPress 自带的 WP_Object_Cache 类,并创建一个新的实例。 这确保了即使 advanced-cache.php 文件没有正确定义对象缓存,WordPress 仍然可以使用默认的对象缓存。

  6. 注册 wp_cache_close 函数: add_action( 'shutdown', 'wp_cache_close' ); 在 WordPress 关闭时执行 wp_cache_close() 函数。这个函数通常用于关闭缓存连接,释放资源。

二、WP_CACHE 常量:对象缓存的开关

WP_CACHE 常量是控制对象缓存是否启用的关键。它需要在 wp-config.php 文件中定义。

define( 'WP_CACHE', true ); // 启用对象缓存
// 或者
define( 'WP_CACHE', false ); // 禁用对象缓存

如果 WP_CACHE 定义为 true,WordPress 就会尝试加载 advanced-cache.php 文件,并使用其中定义的缓存机制。如果 WP_CACHE 没有定义或者定义为 false,WordPress 则会使用默认的 WP_Object_Cache 对象缓存。

三、advanced-cache.php:对象缓存的自定义实现

advanced-cache.php 文件是自定义对象缓存实现的核心。它通常位于 wp-content 目录下,用于替换 WordPress 默认的对象缓存。

一个典型的 advanced-cache.php 文件可能包含以下内容:

<?php
/**
 *  @version 1.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    die( 'No direct access allowed' );
}

global $wp_object_cache;

if ( ! class_exists( 'My_Custom_Object_Cache' ) ) {
    class My_Custom_Object_Cache {

        private $redis;
        private $cache_key_prefix = 'wp_cache:';

        public function __construct() {
            try {
                $this->redis = new Redis();
                $this->redis->connect( '127.0.0.1', 6379 );
            } catch ( Exception $e ) {
                error_log( 'Redis connection failed: ' . $e->getMessage() );
                $this->redis = null;
            }
        }

        public function add( $key, $data, $group = 'default', $expire = 0 ) {
            if ( $this->redis === null ) {
                return false;
            }
            $cache_key = $this->cache_key_prefix . $group . ':' . $key;
            if ( ! $this->redis->exists( $cache_key ) ) {
                return $this->set( $key, $data, $group, $expire );
            }
            return true;
        }

        public function delete( $key, $group = 'default' ) {
            if ( $this->redis === null ) {
                return false;
            }
            $cache_key = $this->cache_key_prefix . $group . ':' . $key;
            return $this->redis->del( $cache_key ) > 0;
        }

        public function get( $key, $group = 'default', $force = false, &$found = null ) {
            if ( $this->redis === null ) {
                return false;
            }
            $cache_key = $this->cache_key_prefix . $group . ':' . $key;
            $value = $this->redis->get( $cache_key );

            if ( $value !== false ) {
                $found = true;
                return maybe_unserialize( $value );
            } else {
                $found = false;
                return false;
            }
        }

        public function set( $key, $data, $group = 'default', $expire = 0 ) {
            if ( $this->redis === null ) {
                return false;
            }
            $cache_key = $this->cache_key_prefix . $group . ':' . $key;
            $value = maybe_serialize( $data );
            if ( $expire > 0 ) {
                return $this->redis->setex( $cache_key, $expire, $value );
            } else {
                return $this->redis->set( $cache_key, $value );
            }
        }

        public function flush() {
            if ( $this->redis === null ) {
                return false;
            }
            // This is a VERY DANGEROUS operation and should be used with caution.
            // It is better to use a key prefix and flush only keys with that prefix.
            // For example: $this->redis->eval("return redis.call('del', unpack(redis.call('keys', 'wp_cache:*')))");
            // However, for simplicity, we'll just flush the entire database here.
            return $this->redis->flushDB();
        }

        public function close() {
            if ( $this->redis !== null ) {
                $this->redis->close();
                $this->redis = null;
            }
        }

        public function incr( $key, $offset = 1, $group = 'default' ) {
            if ( $this->redis === null ) {
                return false;
            }
            $cache_key = $this->cache_key_prefix . $group . ':' . $key;
            return $this->redis->incrBy( $cache_key, $offset );
        }

        public function decr( $key, $offset = 1, $group = 'default' ) {
            if ( $this->redis === null ) {
                return false;
            }
            $cache_key = $this->cache_key_prefix . $group . ':' . $key;
            return $this->redis->decrBy( $cache_key, $offset );
        }

        public function replace( $key, $data, $group = 'default', $expire = 0 ) {
            if ( $this->redis === null ) {
                return false;
            }

            $cache_key = $this->cache_key_prefix . $group . ':' . $key;

            if ( $this->redis->exists( $cache_key ) ) {
                return $this->set( $key, $data, $group, $expire );
            }

            return false;
        }
    }

    $wp_object_cache = new My_Custom_Object_Cache();
}

这个例子使用 Redis 作为缓存后端,定义了一个 My_Custom_Object_Cache 类,实现了 add(), delete(), get(), set(), flush(), close(), incr(), decr(), replace() 这些方法。这些方法是 WordPress 对象缓存 API 的核心,WordPress 使用这些方法来存储和检索数据。

请注意,advanced-cache.php 文件必须定义 $wp_object_cache 全局变量,并将其设置为一个实现了 WordPress 对象缓存 API 的类的实例。

四、WP_Object_Cache 类:WordPress 默认的对象缓存

如果 WP_CACHE 没有启用,或者 advanced-cache.php 文件不存在或没有正确定义对象缓存,WordPress 就会使用默认的 WP_Object_Cache 类。

WP_Object_Cache 类定义在 wp-includes/cache.php 文件中。它使用 PHP 的数组来存储缓存数据,因此只能在单个请求中缓存数据。

虽然 WP_Object_Cache 的性能不如 Memcached 或 Redis 等缓存系统,但它作为一个备选项,确保了即使没有安装任何缓存插件,WordPress 仍然可以使用对象缓存。

五、wp_cache_close() 函数:关闭缓存连接

wp_cache_close() 函数用于关闭缓存连接,释放资源。它通常在 shutdown 钩子上注册,以便在 WordPress 关闭时执行。

function wp_cache_close() {
    global $wp_object_cache;

    /**
     * Fires before the object cache is closed.
     *
     * @since 2.0.0
     */
    do_action( 'close_object_cache' );

    if ( is_object( $wp_object_cache ) && is_callable( array( $wp_object_cache, 'close' ) ) ) {
        $wp_object_cache->close();
    }
}

wp_cache_close() 函数首先触发 close_object_cache 钩子,允许插件在对象缓存关闭之前执行一些操作。然后,它检查 $wp_object_cache 全局变量是否是一个对象,并且该对象是否定义了 close() 方法。如果是,则调用 close() 方法来关闭缓存连接。

六、对象缓存 API:add(), delete(), get(), set()

WordPress 对象缓存 API 提供了一组方法,用于存储和检索数据。这些方法包括:

方法名 描述
add( $key, $data, $group = 'default', $expire = 0 ) 将数据添加到缓存中,如果缓存中已经存在相同的键,则不添加。
delete( $key, $group = 'default' ) 从缓存中删除指定键的数据。
get( $key, $group = 'default', $force = false, &$found = null ) 从缓存中检索指定键的数据。如果 $forcetrue,则强制从数据库中检索数据,忽略缓存。$found 参数用于指示是否在缓存中找到数据。
set( $key, $data, $group = 'default', $expire = 0 ) 将数据存储到缓存中,如果缓存中已经存在相同的键,则覆盖原来的数据。
flush() 清空整个缓存。
close() 关闭缓存连接,释放资源。
incr( $key, $offset = 1, $group = 'default' ) 增加指定键的值。
decr( $key, $offset = 1, $group = 'default' ) 减少指定键的值。
replace( $key, $data, $group = 'default', $expire = 0 ) 替换缓存中指定键的值,如果缓存中不存在该键,则不进行任何操作。

这些方法在 WordPress 核心代码和插件中被广泛使用,用于缓存数据库查询结果、对象数据、瞬态数据等。

七、总结:wp_cache_init() 函数的重要性

wp_cache_init() 函数是 WordPress 对象缓存机制的核心。它负责初始化对象缓存,加载 advanced-cache.php 文件,并确保 WordPress 可以使用对象缓存。

通过理解 wp_cache_init() 函数的工作原理,我们可以更好地配置和优化 WordPress 的对象缓存,从而提高 WordPress 网站的性能。

总的来说,wp_cache_init() 函数就像一个交通警察,指挥着 WordPress 对象缓存的运作。它确保了在启用对象缓存时,advanced-cache.php 文件能够被正确加载,并且 $wp_object_cache 全局变量能够被正确初始化。

好了,今天的讲座就到这里。希望大家对 wp_cache_init() 函数有了更深入的了解。下次再见!

发表回复

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