diff --git a/object-cache.php b/object-cache.php index c8ce99c..290d950 100644 --- a/object-cache.php +++ b/object-cache.php @@ -1,12 +1,10 @@ _exists( $key, $group ) ) { return false; } @@ -622,7 +629,7 @@ public function delete_group( $group ) { * @return bool Always returns true */ public function flush( $redis = true ) { - $this->cache = []; + $this->cache = array(); if ( $redis ) { $this->_call_redis( 'flushdb' ); } @@ -651,14 +658,15 @@ public function get( $key, $group = 'default', $force = false, &$found = null ) $group = 'default'; } - // Key is set internally, so we can use this value. + // Key is set internally, so we can use this value if ( $this->_isset_internal( $key, $group ) && ! $force ) { $this->cache_hits += 1; $found = true; return $this->_get_internal( $key, $group ); } - // Not a persistent group, so don't try Redis if the value doesn't exist internally. + // Not a persistent group, so don't try Redis if the value doesn't exist + // internally if ( ! $this->_should_persist( $group ) ) { $this->cache_misses += 1; $found = false; @@ -673,14 +681,14 @@ public function get( $key, $group = 'default', $force = false, &$found = null ) $value = $this->_call_redis( 'get', $id ); } - // PhpRedis returns `false` when the key doesn't exist. + // PhpRedis returns `false` when the key doesn't exist if ( false === $value ) { $this->cache_misses += 1; $found = false; return false; } - // All non-numeric values are serialized. + // All non-numeric values are serialized $value = is_numeric( $value ) ? intval( $value ) : unserialize( $value ); $this->_set_internal( $key, $group, $value ); @@ -703,7 +711,7 @@ public function get_multiple( $keys, $group = 'default', $force = false ) { $group = 'default'; } - $cache = []; + $cache = array(); if ( ! $this->_should_persist( $group ) ) { foreach ( $keys as $key ) { $cache[ $key ] = $this->_isset_internal( $key, $group ) ? $this->_get_internal( $key, $group ) : false; @@ -731,7 +739,7 @@ public function get_multiple( $keys, $group = 'default', $force = false ) { $results = $this->_call_redis( 'hmGet', $redis_safe_group, $remaining_keys ); $results = is_array( $results ) ? array_values( $results ) : $results; } else { - $ids = []; + $ids = array(); foreach ( $remaining_keys as $key ) { $ids[] = $this->_key( $key, $group ); } @@ -741,7 +749,7 @@ public function get_multiple( $keys, $group = 'default', $force = false ) { foreach ( $remaining_keys as $i => $key ) { $value = isset( $results[ $i ] ) ? $results[ $i ] : false; if ( false !== $value ) { - // All non-numeric values are serialized. + // All non-numeric values are serialized $value = is_numeric( $value ) ? intval( $value ) : unserialize( $value ); $this->_set_internal( $key, $group, $value ); $this->cache_hits++; @@ -751,7 +759,7 @@ public function get_multiple( $keys, $group = 'default', $force = false ) { $cache[ $key ] = $value; } // Make sure return values are returned in the order of the passed keys. - $return_cache = []; + $return_cache = array(); foreach ( $keys as $key ) { $return_cache[ $key ] = isset( $cache[ $key ] ) ? $cache[ $key ] : false; } @@ -772,7 +780,7 @@ public function incr( $key, $offset = 1, $group = 'default' ) { $group = 'default'; } - // The key needs to exist in order to be incremented. + // The key needs to exist in order to be incremented if ( ! $this->_exists( $key, $group ) ) { return false; } @@ -818,7 +826,6 @@ public function incr( $key, $offset = 1, $group = 'default' ) { /** * Replace the contents in the cache, if contents already exist - * * @see WP_Object_Cache::set() * * @param int|string $key What to call the contents in the cache @@ -888,7 +895,7 @@ public function set( $key, $data, $group = 'default', $expire = WP_REDIS_DEFAULT $data = serialize( $data ); } - // Redis doesn't support expire on hash group keys. + // Redis doesn't support expire on hash group keys if ( $this->_should_use_redis_hashes( $group ) ) { $redis_safe_group = $this->_key( '', $group ); $this->_call_redis( 'hSet', $redis_safe_group, $key, $data ); @@ -915,7 +922,7 @@ public function stats() { foreach ( $this->redis_calls as $method => $calls ) { $total_redis_calls += $calls; } - $out = []; + $out = array(); $out[] = '

'; $out[] = 'Cache Hits:' . (int) $this->cache_hits . '
'; $out[] = 'Cache Misses:' . (int) $this->cache_misses . '
'; @@ -930,7 +937,9 @@ public function stats() { $out[] = '

  • Group: ' . esc_html( $group ) . ' - ( ' . number_format( strlen( serialize( $cache ) ) / 1024, 2 ) . 'k )
  • '; } $out[] = ''; - echo implode( PHP_EOL, $out ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + // @codingStandardsIgnoreStart + echo implode( PHP_EOL, $out ); + // @codingStandardsIgnoreEnd } /** @@ -948,9 +957,6 @@ public function switch_to_blog( $blog_id ) { /** * Utility function to determine whether a key exists in the cache. * - * @param string $key The key to check for existence. - * @param string $group The group to which the key belongs. - * * @access protected */ protected function _exists( $key, $group ) { @@ -973,8 +979,8 @@ protected function _exists( $key, $group ) { /** * Check whether there's a value in the internal object cache. * - * @param string $key The key to check for existence. - * @param string $group The group to which the key belongs. + * @param string $key + * @param string $group * @return boolean */ protected function _isset_internal( $key, $group ) { @@ -990,8 +996,8 @@ protected function _isset_internal( $key, $group ) { /** * Get a value from the internal object cache * - * @param string $key The key to the value to get. - * @param string $group The group to which the key belongs. + * @param string $key + * @param string $group * @return mixed */ protected function _get_internal( $key, $group ) { @@ -1016,15 +1022,15 @@ protected function _get_internal( $key, $group ) { /** * Set a value to the internal object cache * - * @param string $key The key to the value to set. - * @param string $group The group to which the key belongs. - * @param mixed $value The value to set. + * @param string $key + * @param string $group + * @param mixed $value */ protected function _set_internal( $key, $group, $value ) { if ( $this->_should_use_redis_hashes( $group ) ) { $multisite_safe_group = $this->multisite && ! isset( $this->global_groups[ $group ] ) ? $this->blog_prefix . $group : $group; if ( ! isset( $this->cache[ $multisite_safe_group ] ) ) { - $this->cache[ $multisite_safe_group ] = []; + $this->cache[ $multisite_safe_group ] = array(); } $this->cache[ $multisite_safe_group ][ $key ] = $value; } else { @@ -1036,8 +1042,8 @@ protected function _set_internal( $key, $group, $value ) { /** * Unset a value from the internal object cache * - * @param string $key The key to the value to unset. - * @param string $group The group to which the key belongs. + * @param string $key + * @param string $group */ protected function _unset_internal( $key, $group ) { if ( $this->_should_use_redis_hashes( $group ) ) { @@ -1103,7 +1109,7 @@ protected function _should_use_redis_hashes( $group ) { protected function _connect_redis() { global $redis_server; - $check_dependencies = [ $this, 'check_client_dependencies' ]; + $check_dependencies = array( $this, 'check_client_dependencies' ); /** * Permits alternate dependency check mechanism to be used. * @@ -1119,34 +1125,34 @@ protected function _connect_redis() { $client_parameters = $this->build_client_parameters( $redis_server ); try { - $client_connection = [ $this, 'prepare_client_connection' ]; + $client_connection = array( $this, 'prepare_client_connection' ); /** * Permits alternate initial client connection mechanism to be used. * * @param callable $client_connection Callback to execute. */ $client_connection = apply_filters( 'wp_redis_prepare_client_connection_callback', $client_connection ); - $this->redis = call_user_func_array( $client_connection, [ $client_parameters ] ); + $this->redis = call_user_func_array( $client_connection, array( $client_parameters ) ); } catch ( Exception $e ) { $this->_exception_handler( $e ); $this->is_redis_connected = false; return $this->is_redis_connected; } - $keys_methods = [ + $keys_methods = array( 'auth' => 'auth', 'database' => 'select', - ]; + ); try { - $setup_connection = [ $this, 'perform_client_connection' ]; + $setup_connection = array( $this, 'perform_client_connection' ); /** * Permits alternate setup client connection mechanism to be used. * * @param callable $setup_connection Callback to execute. */ $setup_connection = apply_filters( 'wp_redis_perform_client_connection_callback', $setup_connection ); - call_user_func_array( $setup_connection, [ $this->redis, $client_parameters, $keys_methods ] ); + call_user_func_array( $setup_connection, array( $this->redis, $client_parameters, $keys_methods ) ); } catch ( Exception $e ) { $this->_exception_handler( $e ); $this->is_redis_connected = false; @@ -1185,37 +1191,38 @@ public function build_client_parameters( $redis_server ) { if ( empty( $redis_server ) ) { // Attempt to automatically load Pantheon's Redis config from the env. if ( isset( $_SERVER['CACHE_HOST'] ) ) { - $redis_server = [ - 'host' => isset( $_SERVER['CACHE_HOST'] ) ? sanitize_text_field( $_SERVER['CACHE_HOST'] ) : 0, - 'port' => isset( $_SERVER['CACHE_PORT'] ) ? sanitize_text_field( $_SERVER['CACHE_PORT'] ) : 0, - 'auth' => isset( $_SERVER['CACHE_PASSWORD'] ) ? sanitize_text_field( $_SERVER['CACHE_PASSWORD'] ) : 0, - 'database' => isset( $_SERVER['CACHE_DB'] ) ? sanitize_text_field( $_SERVER['CACHE_DB'] ) : 0, - ]; + $redis_server = array( + 'host' => $_SERVER['CACHE_HOST'], + 'port' => $_SERVER['CACHE_PORT'], + 'auth' => $_SERVER['CACHE_PASSWORD'], + 'database' => isset( $_SERVER['CACHE_DB'] ) ? $_SERVER['CACHE_DB'] : 0, + ); } else { - $redis_server = [ - 'host' => '127.0.0.1', - 'port' => 6379, + $redis_server = array( + 'host' => '127.0.0.1', + 'port' => 6379, 'database' => 0, - ]; + ); } } - if ( file_exists( $redis_server['host'] ) && 'socket' === filetype( $redis_server['host'] ) ) { // unix socket connection. - // port must be null or socket won't connect. + if ( file_exists( $redis_server['host'] ) && 'socket' === filetype( $redis_server['host'] ) ) { //unix socket connection + //port must be null or socket won't connect $port = null; - } else { // tcp connection. + } else { //tcp connection $port = ! empty( $redis_server['port'] ) ? $redis_server['port'] : 6379; } - $defaults = [ - 'host' => $redis_server['host'], - 'port' => $port, - 'timeout' => 1000, // I multiplied this by 1000 so we'd have a common measure of ms instead of s and ms, need to make sure this gets divided by 1000. + $defaults = array( + 'host' => $redis_server['host'], + 'port' => $port, + 'timeout' => 1000, // I multiplied this by 1000 so we'd have a common measure of ms instead of s and ms, need to make sure this gets divided by 1000 'retry_interval' => 100, - ]; - // 1s timeout, 100ms delay between reconnections. + ); + // 1s timeout, 100ms delay between reconnections - // merging the defaults with the original $redis_server enables any custom parameters to get sent downstream to the redis client. + // merging the defaults with the original $redis_server enables any + // custom parameters to get sent downstream to the redis client. return array_replace_recursive( $redis_server, $defaults ); } @@ -1227,15 +1234,16 @@ public function build_client_parameters( $redis_server ) { */ public function prepare_client_connection( $client_parameters ) { if ( defined( 'WP_REDIS_USE_RELAY' ) && WP_REDIS_USE_RELAY ) { - $redis = new Relay\Relay(); + $redis = new Relay\Relay; } else { - $redis = new Redis(); + $redis = new Redis; } $redis->connect( $client_parameters['host'], $client_parameters['port'], - // $client_parameters['timeout'] is sent in milliseconds, connect() takes seconds, so divide by 1000. + // $client_parameters['timeout'] is sent in milliseconds, + // connect() takes seconds, so divide by 1000 $client_parameters['timeout'] / 1000, null, $client_parameters['retry_interval'] @@ -1251,7 +1259,6 @@ public function prepare_client_connection( $client_parameters ) { * @param array $client_parameters Parameters used to configure Redis. * @param array $keys_methods Associative array of keys from * $client_parameters to use as method arguments for $redis. - * @throws Exception If the connection fails. * @return bool True if successful. */ public function perform_client_connection( $redis, $client_parameters, $keys_methods ) { @@ -1274,17 +1281,17 @@ public function perform_client_connection( $redis, $client_parameters, $keys_met /** * Wrapper method for calls to Redis, which fails gracefully when Redis is unavailable * - * @param string $method The name of the Redis method to call. - * @throws Exception If the connection fails. - * @return mixed The return value of the Redis method, or false if Redis is unavailable. + * @param string $method + * @param mixed $args + * @return mixed */ protected function _call_redis( $method ) { global $wpdb; $arguments = func_get_args(); - array_shift( $arguments ); // ignore $method. + array_shift( $arguments ); // ignore $method - // $group is intended for the failback, and isn't passed to the Redis callback. + // $group is intended for the failback, and isn't passed to the Redis callback if ( 'hIncrBy' === $method ) { $group = array_pop( $arguments ); } @@ -1295,7 +1302,7 @@ protected function _call_redis( $method ) { $this->redis_calls[ $method ] = 0; } $this->redis_calls[ $method ]++; - $retval = call_user_func_array( [ $this->redis, $method ], $arguments ); + $retval = call_user_func_array( array( $this->redis, $method ), $arguments ); return $retval; } catch ( Exception $e ) { $retry_exception_messages = $this->retry_exception_messages(); @@ -1305,16 +1312,17 @@ protected function _call_redis( $method ) { $this->_exception_handler( $e ); - // Attempt to refresh the connection if it was successfully established once $this->is_redis_connected will be set inside _connect_redis(). + // Attempt to refresh the connection if it was successfully established once + // $this->is_redis_connected will be set inside _connect_redis() if ( $this->_connect_redis() ) { - return call_user_func_array( [ $this, '_call_redis' ], array_merge( [ $method ], $arguments ) ); + return call_user_func_array( array( $this, '_call_redis' ), array_merge( array( $method ), $arguments ) ); } - // Fall through to fallback below. + // Fall through to fallback below } else { throw $e; } } - } // End if. + } // End if(). if ( $this->is_redis_failback_flush_enabled() && ! $this->do_redis_failback_flush && ! empty( $wpdb ) ) { if ( $this->multisite ) { @@ -1326,11 +1334,13 @@ protected function _call_redis( $method ) { $col1 = 'option_name'; $col2 = 'option_value'; } + // @codingStandardsIgnoreStart $wpdb->query( "INSERT IGNORE INTO {$table} ({$col1},{$col2}) VALUES ('wp_redis_do_redis_failback_flush',1)" ); + // @codingStandardsIgnoreEnd $this->do_redis_failback_flush = true; } - // Mock expected behavior from Redis for these methods. + // Mock expected behavior from Redis for these methods switch ( $method ) { case 'incr': case 'incrBy': @@ -1369,7 +1379,7 @@ protected function _call_redis( $method ) { * @return array Array of expected exception messages */ public function retry_exception_messages() { - $retry_exception_messages = [ 'socket error on read socket', 'Connection closed', 'Redis server went away' ]; + $retry_exception_messages = array( 'socket error on read socket', 'Connection closed', 'Redis server went away' ); return apply_filters( 'wp_redis_retry_exception_messages', $retry_exception_messages ); } @@ -1407,16 +1417,20 @@ protected function _format_message_for_pattern( $message ) { /** * Handles exceptions by triggering a php error. * - * @param Exception $exception The exception to handle. - * @return void + * @param Exception $exception + * @return null */ protected function _exception_handler( $exception ) { try { $this->last_triggered_error = 'WP Redis: ' . $exception->getMessage(); - // Be friendly to developers debugging production servers by triggering an error. - trigger_error( esc_html( $this->last_triggered_error ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error - } catch ( PHPUnit_Framework_Error_Warning $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch - // PHPUnit throws an Exception when `trigger_error()` is called. To ensure our tests (which expect Exceptions to be caught) continue to run, we catch the PHPUnit exception and inspect the RedisException message. + // Be friendly to developers debugging production servers by triggering an error + // @codingStandardsIgnoreStart + trigger_error( $this->last_triggered_error, E_USER_WARNING ); + // @codingStandardsIgnoreEnd + } catch ( PHPUnit_Framework_Error_Warning $e ) { + // PHPUnit throws an Exception when `trigger_error()` is called. + // To ensure our tests (which expect Exceptions to be caught) continue to run, + // we catch the PHPUnit exception and inspect the RedisException message } } @@ -1446,6 +1460,8 @@ private function is_redis_failback_flush_enabled() { /** * Sets up object properties; PHP 5 style constructor + * + * @return null|WP_Object_Cache If cache is disabled, returns null. */ public function __construct() { global $blog_id, $table_prefix, $wpdb; @@ -1454,7 +1470,7 @@ public function __construct() { $this->blog_prefix = $this->multisite ? $blog_id . ':' : ''; if ( ! $this->_connect_redis() && function_exists( 'add_action' ) ) { - add_action( 'admin_notices', [ $this, 'wp_action_admin_notices_warn_missing_redis' ] ); + add_action( 'admin_notices', array( $this, 'wp_action_admin_notices_warn_missing_redis' ) ); } if ( $this->is_redis_failback_flush_enabled() && ! empty( $wpdb ) ) { @@ -1467,11 +1483,15 @@ public function __construct() { $col1 = 'option_name'; $col2 = 'option_value'; } + // @codingStandardsIgnoreStart $this->do_redis_failback_flush = (bool) $wpdb->get_results( "SELECT {$col2} FROM {$table} WHERE {$col1}='wp_redis_do_redis_failback_flush'" ); + // @codingStandardsIgnoreEnd if ( $this->is_redis_connected && $this->do_redis_failback_flush ) { $ret = $this->_call_redis( 'flushdb' ); if ( $ret ) { + // @codingStandardsIgnoreStart $wpdb->query( "DELETE FROM {$table} WHERE {$col1}='wp_redis_do_redis_failback_flush'" ); + // @codingStandardsIgnoreEnd $this->do_redis_failback_flush = false; } } @@ -1479,8 +1499,11 @@ public function __construct() { $this->global_prefix = ( $this->multisite || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) ) ? '' : $table_prefix; - // @todo This should be moved to the PHP4 style constructor, PHP5 - register_shutdown_function( [ $this, '__destruct' ] ); + /** + * @todo This should be moved to the PHP4 style constructor, PHP5 + * already calls __destruct() + */ + register_shutdown_function( array( $this, '__destruct' ) ); } /**