@@ -76,6 +76,12 @@ function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
7676 return $ wp_object_cache ->get ( $ key , $ group , $ force , $ found );
7777}
7878
79+ function wp_cache_get_multiple ( $ keys , $ group = '' , $ force = false ) {
80+ global $ wp_object_cache ;
81+
82+ return $ wp_object_cache ->get_multiple ( $ keys , $ group , $ force );
83+ }
84+
7985/**
8086 * Retrieve multiple cache entries
8187 *
@@ -483,6 +489,25 @@ function get( $id, $group = 'default', $force = false, &$found = null ) {
483489 if ( false === $ flags ) {
484490 $ found = false ;
485491 $ value = false ;
492+ } elseif ( false === $ value && ( $ flags & 0xFF01 ) === 0x01 ) {
493+ /*
494+ * The lowest byte is used for flags.
495+ * 0x01 means the value is serialized (MMC_SERIALIZED).
496+ * The second lowest indicates data type: 0 is string, 1 is bool, 3 is long, 7 is double.
497+ * `null` is serialized into a string, thus $flags is 0x0001
498+ * Empty string will correspond to $flags = 0x0000 (not serialized).
499+ * For `false` or `true` $flags will be 0x0100
500+ *
501+ * See:
502+ * - https://github.com/websupport-sk/pecl-memcache/blob/2a5de3c5d9c0bd0acbcf7e6e0b7570f15f89f55b/php7/memcache_pool.h#L61-L76 - PHP 7.x
503+ * - https://github.com/websupport-sk/pecl-memcache/blob/ccf702b14b18fce18a1863e115a7b4c964df952e/src/memcache_pool.h#L57-L76 - PHP 8.x
504+ *
505+ * In PHP 8, they changed the way memcache_get() handles `null`:
506+ * https://github.com/websupport-sk/pecl-memcache/blob/ccf702b14b18fce18a1863e115a7b4c964df952e/src/memcache.c#L2175-L2177
507+ *
508+ * If the return value is `null`, it is silently converted to `false`. We can only rely upon $flags to find out whether `false` is real.
509+ */
510+ $ value = null ;
486511 }
487512
488513 $ this ->cache [ $ key ] = [
@@ -572,6 +597,57 @@ function get_multi( $groups ) {
572597 return $ return ;
573598 }
574599
600+ public function get_multiple ( $ keys , $ group = 'default ' , $ force = false ) {
601+ $ mc = $ this ->get_mc ( $ group );
602+
603+ $ no_mc = in_array ( $ group , $ this ->no_mc_groups , true );
604+
605+ $ uncached_keys = array ();
606+ $ return = array ();
607+ $ return_cache = array ();
608+
609+ foreach ( $ keys as $ id ) {
610+ $ key = $ this ->key ( $ id , $ group );
611+
612+ if ( isset ( $ this ->cache [ $ key ] ) && ( ! $ force || $ no_mc ) ) {
613+ $ value = $ this ->cache [ $ key ]['found ' ] ? $ this ->cache [ $ key ]['value ' ] : false ;
614+ $ return [ $ id ] = is_object ( $ value ) ? clone $ value : $ value ;
615+ } else if ( $ no_mc ) {
616+ $ return [ $ id ] = false ;
617+ $ return_cache [ $ key ] = [
618+ 'value ' => false ,
619+ 'found ' => false ,
620+ ];
621+ } else {
622+ $ uncached_keys [ $ id ] = $ key ;
623+ }
624+ }
625+
626+ if ( $ uncached_keys ) {
627+ $ this ->timer_start ();
628+ $ uncached_keys_list = array_values ( $ uncached_keys );
629+ $ values = $ mc ->get ( $ uncached_keys_list );
630+ $ elapsed = $ this ->timer_stop ();
631+
632+ $ this ->group_ops_stats ( 'get_multiple ' , $ uncached_keys_list , $ group , null , $ elapsed );
633+
634+ foreach ( $ uncached_keys as $ id => $ key ) {
635+ $ found = array_key_exists ( $ key , $ values );
636+ $ value = $ found ? $ values [ $ key ] : false ;
637+
638+ $ return [ $ id ] = $ value ;
639+ $ return_cache [ $ key ] = [
640+ 'value ' => $ value ,
641+ 'found ' => $ found ,
642+ ];
643+ }
644+ }
645+
646+ $ this ->cache = array_merge ( $ this ->cache , $ return_cache );
647+
648+ return $ return ;
649+ }
650+
575651 function flush_prefix ( $ group ) {
576652 if ( $ group === $ this ->flush_group || $ group === $ this ->global_flush_group ) {
577653 // Never flush the flush numbers.
@@ -694,6 +770,7 @@ function colorize_debug_line( $line, $trailing_html = '' ) {
694770 'get ' => 'green ' ,
695771 'get_local ' => 'lightgreen ' ,
696772 'get_multi ' => 'fuchsia ' ,
773+ 'get_multiple ' => 'navy ' ,
697774 'set ' => 'purple ' ,
698775 'set_local ' => 'orchid ' ,
699776 'add ' => 'blue ' ,
0 commit comments