ProtocolProcessor.php 3.8 KB

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