ProtocolProcessor.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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\Protocol\Text;
  11. use Predis\CommunicationException;
  12. use Predis\Command\CommandInterface;
  13. use Predis\Connection\ComposableConnectionInterface;
  14. use Predis\Protocol\ProtocolException;
  15. use Predis\Protocol\ProtocolProcessorInterface;
  16. use Predis\Response;
  17. use Predis\Response\Iterator;
  18. /**
  19. * Protocol processor for the standard Redis wire protocol.
  20. *
  21. * @link http://redis.io/topics/protocol
  22. * @author Daniele Alessandri <suppakilla@gmail.com>
  23. */
  24. class ProtocolProcessor implements ProtocolProcessorInterface
  25. {
  26. protected $mbiterable;
  27. protected $serializer;
  28. /**
  29. *
  30. */
  31. public function __construct()
  32. {
  33. $this->mbiterable = false;
  34. $this->serializer = new RequestSerializer();
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function write(ComposableConnectionInterface $connection, CommandInterface $command)
  40. {
  41. $request = $this->serializer->serialize($command);
  42. $connection->writeBytes($request);
  43. }
  44. /**
  45. * {@inheritdoc}
  46. */
  47. public function read(ComposableConnectionInterface $connection)
  48. {
  49. $chunk = $connection->readLine();
  50. $prefix = $chunk[0];
  51. $payload = substr($chunk, 1);
  52. switch ($prefix) {
  53. case '+': // inline
  54. switch ($payload) {
  55. case 'OK':
  56. return true;
  57. case 'QUEUED':
  58. return new Response\StatusQueued();
  59. default:
  60. return $payload;
  61. }
  62. case '$': // bulk
  63. $size = (int) $payload;
  64. if ($size === -1) {
  65. return null;
  66. }
  67. return substr($connection->readBytes($size + 2), 0, -2);
  68. case '*': // multi bulk
  69. $count = (int) $payload;
  70. if ($count === -1) {
  71. return null;
  72. }
  73. if ($this->mbiterable) {
  74. return new Iterator\MultiBulk($connection, $count);
  75. }
  76. $multibulk = array();
  77. for ($i = 0; $i < $count; $i++) {
  78. $multibulk[$i] = $this->read($connection);
  79. }
  80. return $multibulk;
  81. case ':': // integer
  82. return (int) $payload;
  83. case '-': // error
  84. return new Response\Error($payload);
  85. default:
  86. CommunicationException::handle(new ProtocolException(
  87. $connection, "Unknown prefix: '$prefix'"
  88. ));
  89. }
  90. }
  91. /**
  92. * Enables or disables returning multibulk responses as specialized PHP
  93. * iterators used to stream bulk elements of a multibulk response instead
  94. * returning a plain array.
  95. *
  96. * Please note that streamable multibulk replies are not globally supported
  97. * by the abstractions built-in into Predis such as for transactions or
  98. * pipelines. Use them with care!
  99. *
  100. * @param bool $value Enable or disable streamable multibulk responses.
  101. */
  102. public function useIterableMultibulk($value)
  103. {
  104. $this->mbiterable = (bool) $value;
  105. }
  106. }