ProtocolProcessor.php 3.5 KB

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