99use Redis ;
1010use RedisCluster ;
1111use RedisException ;
12+ use RuntimeException ;
13+ use UnexpectedValueException ;
1214
1315/**
1416 * @mixin \Redis
@@ -29,6 +31,27 @@ class PhpRedisConnection extends Connection implements ConnectionContract
2931 */
3032 protected $ config ;
3133
34+ /**
35+ * In memory cache of version check whether phpredis supports packing and unpacking.
36+ *
37+ * @var bool|null
38+ */
39+ private $ supportsPack = null ;
40+
41+ /**
42+ * In memory cache of version check whether phpredis supports lzf compression.
43+ *
44+ * @var bool|null
45+ */
46+ private $ supportsLzf = null ;
47+
48+ /**
49+ * In memory cache of version check whether phpredis supports zstd compression.
50+ *
51+ * @var bool|null
52+ */
53+ private $ supportsZstd = null ;
54+
3255 /**
3356 * Create a new PhpRedis connection.
3457 *
@@ -573,4 +596,138 @@ public function __call($method, $parameters)
573596 {
574597 return parent ::__call (strtolower ($ method ), $ parameters );
575598 }
599+
600+ /**
601+ * Prepares values to be used with e.g. the `eval` command, because the
602+ * phpredis extension does not do it for us. This includes serialization and
603+ * compression if any of those settings are configured.
604+ *
605+ * @param array<int|string,string> $values
606+ * @return array<int|string,string>
607+ */
608+ public function pack (array $ values ): array
609+ {
610+ if (empty ($ values )) {
611+ return $ values ;
612+ }
613+
614+ if ($ this ->supportsPack ()) {
615+ return array_map ([$ this ->client , '_pack ' ], $ values );
616+ }
617+
618+ if ($ this ->compressed ()) {
619+ if ($ this ->supportsLzf () && $ this ->lzfCompressed ()) {
620+ if (! function_exists ('lzf_compress ' )) {
621+ throw new RuntimeException ("Missing 'lzf' extension to call 'lzf_compress'. " );
622+ }
623+
624+ $ processor = function ($ value ) {
625+ return \lzf_compress ($ this ->client ->_serialize ($ value ));
626+ };
627+ } elseif ($ this ->supportsZstd () && $ this ->zstdCompressed ()) {
628+ if (! function_exists ('zstd_compress ' )) {
629+ throw new RuntimeException ("Missing 'zstd' extension to call 'zstd_compress'. " );
630+ }
631+
632+ $ compressionLevel = $ this ->client ->getOption (Redis::OPT_COMPRESSION_LEVEL );
633+ $ processor = function ($ value ) use ($ compressionLevel ) {
634+ return \zstd_compress (
635+ $ this ->client ->_serialize ($ value ),
636+ $ compressionLevel === 0 ? Redis::COMPRESSION_ZSTD_DEFAULT : $ compressionLevel
637+ );
638+ };
639+ } else {
640+ throw new UnexpectedValueException (sprintf (
641+ 'Not supported phpredis compression in use [%d]. ' ,
642+ $ this ->client ->getOption (Redis::OPT_COMPRESSION )
643+ ));
644+ }
645+ } else {
646+ $ processor = function ($ value ) {
647+ return $ this ->client ->_serialize ($ value );
648+ };
649+ }
650+
651+ return array_map ($ processor , $ values );
652+ }
653+
654+ /**
655+ * Determine if compression is enabled.
656+ *
657+ * @return bool
658+ */
659+ public function compressed (): bool
660+ {
661+ return defined ('Redis::OPT_COMPRESSION ' ) &&
662+ $ this ->client ->getOption (Redis::OPT_COMPRESSION ) !== Redis::COMPRESSION_NONE ;
663+ }
664+
665+ /**
666+ * Determine if LZF compression is enabled.
667+ *
668+ * @return bool
669+ */
670+ public function lzfCompressed (): bool
671+ {
672+ return defined ('Redis::COMPRESSION_LZF ' ) &&
673+ $ this ->client ->getOption (Redis::OPT_COMPRESSION ) === Redis::COMPRESSION_LZF ;
674+ }
675+
676+ /**
677+ * Determine if ZSTD compression is enabled.
678+ *
679+ * @return bool
680+ */
681+ public function zstdCompressed (): bool
682+ {
683+ return defined ('Redis::COMPRESSION_ZSTD ' ) &&
684+ $ this ->client ->getOption (Redis::OPT_COMPRESSION ) === Redis::COMPRESSION_ZSTD ;
685+ }
686+
687+ /**
688+ * Determine if LZ4 compression is enabled.
689+ *
690+ * @return bool
691+ */
692+ public function lz4Compressed (): bool
693+ {
694+ return defined ('Redis::COMPRESSION_LZ4 ' ) &&
695+ $ this ->client ->getOption (Redis::OPT_COMPRESSION ) === Redis::COMPRESSION_LZ4 ;
696+ }
697+
698+ private function supportsPack (): bool
699+ {
700+ if ($ this ->supportsPack === null ) {
701+ $ phpredisVersion = phpversion ('redis ' );
702+
703+ $ this ->supportsPack =
704+ ($ phpredisVersion !== false && version_compare ($ phpredisVersion , '5.3.5 ' , '>= ' ));
705+ }
706+
707+ return $ this ->supportsPack ;
708+ }
709+
710+ private function supportsLzf (): bool
711+ {
712+ if ($ this ->supportsLzf === null ) {
713+ $ phpredisVersion = phpversion ('redis ' );
714+
715+ $ this ->supportsLzf =
716+ ($ phpredisVersion !== false && version_compare ($ phpredisVersion , '4.3.0 ' , '>= ' ));
717+ }
718+
719+ return $ this ->supportsLzf ;
720+ }
721+
722+ private function supportsZstd (): bool
723+ {
724+ if ($ this ->supportsZstd === null ) {
725+ $ phpredisVersion = phpversion ('redis ' );
726+
727+ $ this ->supportsZstd =
728+ ($ phpredisVersion !== false && version_compare ($ phpredisVersion , '5.1.0 ' , '>= ' ));
729+ }
730+
731+ return $ this ->supportsZstd ;
732+ }
576733}
0 commit comments