TextProtocol.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. <?php
  2. namespace Predis\Protocols\Text;
  3. use Predis\Helpers;
  4. use Predis\ResponseError;
  5. use Predis\ResponseQueued;
  6. use Predis\ServerException;
  7. use Predis\ProtocolException;
  8. use Predis\Commands\ICommand;
  9. use Predis\Protocols\IProtocolProcessor;
  10. use Predis\Network\IConnectionComposable;
  11. use Predis\Iterators\MultiBulkResponseSimple;
  12. class TextProtocol implements IProtocolProcessor {
  13. const NEWLINE = "\r\n";
  14. const OK = 'OK';
  15. const ERROR = 'ERR';
  16. const QUEUED = 'QUEUED';
  17. const NULL = 'nil';
  18. const PREFIX_STATUS = '+';
  19. const PREFIX_ERROR = '-';
  20. const PREFIX_INTEGER = ':';
  21. const PREFIX_BULK = '$';
  22. const PREFIX_MULTI_BULK = '*';
  23. const BUFFER_SIZE = 4096;
  24. private $_mbiterable, $_throwErrors, $_serializer;
  25. public function __construct() {
  26. $this->_mbiterable = false;
  27. $this->_throwErrors = true;
  28. $this->_serializer = new TextCommandSerializer();
  29. }
  30. public function write(IConnectionComposable $connection, ICommand $command) {
  31. $connection->writeBytes($this->_serializer->serialize($command));
  32. }
  33. public function read(IConnectionComposable $connection) {
  34. $chunk = $connection->readLine();
  35. $prefix = $chunk[0];
  36. $payload = substr($chunk, 1);
  37. switch ($prefix) {
  38. case '+': // inline
  39. switch ($payload) {
  40. case 'OK':
  41. return true;
  42. case 'QUEUED':
  43. return new ResponseQueued();
  44. default:
  45. return $payload;
  46. }
  47. case '$': // bulk
  48. $size = (int) $payload;
  49. if ($size === -1) {
  50. return null;
  51. }
  52. return substr($connection->readBytes($size + 2), 0, -2);
  53. case '*': // multi bulk
  54. $count = (int) $payload;
  55. if ($count === -1) {
  56. return null;
  57. }
  58. if ($this->_mbiterable == true) {
  59. return new MultiBulkResponseSimple($connection, $count);
  60. }
  61. $multibulk = array();
  62. for ($i = 0; $i < $count; $i++) {
  63. $multibulk[$i] = $this->read($connection);
  64. }
  65. return $multibulk;
  66. case ':': // integer
  67. return (int) $payload;
  68. case '-': // error
  69. if ($this->_throwErrors) {
  70. throw new ServerException($payload);
  71. }
  72. return new ResponseError($payload);
  73. default:
  74. Helpers::onCommunicationException(new ProtocolException(
  75. $connection, "Unknown prefix: '$prefix'"
  76. ));
  77. }
  78. }
  79. public function setOption($option, $value) {
  80. switch ($option) {
  81. case 'iterable_multibulk':
  82. $this->_mbiterable = (bool) $value;
  83. break;
  84. case 'throw_errors':
  85. $this->_throwErrors = (bool) $value;
  86. break;
  87. }
  88. }
  89. }