KeyspaceIterator.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <?php
  2. /*
  3. * This file is part of the Predis package.
  4. *
  5. * (c) Daniele Alessandri <suppakilla@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Predis\Iterator\Scan;
  11. use Iterator;
  12. use Predis\ClientInterface;
  13. use Predis\NotSupportedException;
  14. /**
  15. * Abstracts the iteration of the keyspace on a Redis instance
  16. * by leveraging the SCAN command (Redis >= 2.8) wrapped in a
  17. * fully-rewindable PHP iterator.
  18. *
  19. * @author Daniele Alessandri <suppakilla@gmail.com>
  20. * @link http://redis.io/commands/scan
  21. */
  22. class KeyspaceIterator implements Iterator
  23. {
  24. protected $client;
  25. protected $match;
  26. protected $count;
  27. protected $valid;
  28. protected $scanmore;
  29. protected $elements;
  30. protected $position;
  31. protected $cursor;
  32. /**
  33. * @param ClientInterface $client Client connected to Redis.
  34. * @param string $match Pattern to match during the server-side iteration.
  35. * @param int $count Hints used by Redis to compute the number of results per iteration.
  36. */
  37. public function __construct(ClientInterface $client, $match = null, $count = null)
  38. {
  39. if (!$client->getProfile()->supportsCommand('SCAN')) {
  40. throw new NotSupportedException('The specified server profile does not support the SCAN command.');
  41. }
  42. $this->client = $client;
  43. $this->match = $match;
  44. $this->count = $count;
  45. $this->reset();
  46. }
  47. /**
  48. * Resets the inner state of the iterator.
  49. */
  50. protected function reset()
  51. {
  52. $this->valid = true;
  53. $this->scanmore = true;
  54. $this->elements = array();
  55. $this->position = -1;
  56. $this->cursor = 0;
  57. }
  58. /**
  59. * Returns an array of options for the SCAN command.
  60. *
  61. * @return array
  62. */
  63. protected function getScanOptions()
  64. {
  65. $options = array();
  66. if (strlen($this->match) > 0) {
  67. $options['MATCH'] = $this->match;
  68. }
  69. if ($this->count > 0) {
  70. $options['COUNT'] = $this->count;
  71. }
  72. return $options;
  73. }
  74. /**
  75. * Performs a new SCAN to fetch new elements in the collection from
  76. * Redis, effectively advancing the iteration process.
  77. *
  78. * @return array
  79. */
  80. protected function executeScanCommand()
  81. {
  82. return $this->client->scan($this->cursor, $this->getScanOptions());
  83. }
  84. /**
  85. * Populates the local buffer of elements fetched from the server
  86. * during the iteration.
  87. */
  88. protected function feed()
  89. {
  90. list($cursor, $elements) = $this->executeScanCommand();
  91. if (!$cursor) {
  92. $this->scanmore = false;
  93. }
  94. $this->cursor = $cursor;
  95. $this->elements = $elements;
  96. }
  97. /**
  98. * {@inheritdoc}
  99. */
  100. public function rewind()
  101. {
  102. $this->reset();
  103. $this->next();
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. public function current()
  109. {
  110. return $this->current;
  111. }
  112. /**
  113. * {@inheritdoc}
  114. */
  115. public function key()
  116. {
  117. return $this->position;
  118. }
  119. /**
  120. * {@inheritdoc}
  121. */
  122. public function next()
  123. {
  124. if (!$this->elements && $this->scanmore) {
  125. $this->feed();
  126. }
  127. if ($this->elements) {
  128. $this->position++;
  129. $this->current = array_shift($this->elements);
  130. } else {
  131. $this->valid = false;
  132. }
  133. }
  134. /**
  135. * {@inheritdoc}
  136. */
  137. public function valid()
  138. {
  139. return $this->valid;
  140. }
  141. }