public function command($name, $args, $cb = null)
{
if ($name === 'MULTI' || $name === 'WATCH') {
$this->acquire();
} elseif (mb_orig_substr($name, -9) === 'SUBSCRIBE') {
if (!$this->subscribed) {
$this->subscribed = true;
$this->pool->servConnSub[$this->url] = $this;
$this->acquire();
$this->setTimeouts(86400, 86400);
// @TODO: remove timeout
}
$opcb = null;
for ($i = sizeof($args) - 1; $i >= 0; --$i) {
$a = $args[$i];
if ((is_array($a) || is_object($a)) && is_callable($a)) {
$opcb = $cb;
$cb = CallbackWrapper::wrap($a);
$args = array_slice($args, 0, $i);
break;
} elseif ($a !== null) {
break;
}
}
}
if ($name === 'SUBSCRIBE') {
$this->subscribed();
$channels = [];
foreach ($args as $arg) {
if (!is_array($arg)) {
$arg = [$arg];
}
foreach ($arg as $chan) {
$b = !isset($this->subscribeCb[$chan]);
CallbackWrapper::addToArray($this->subscribeCb[$chan], $cb);
if ($b) {
$channels[] = $chan;
} else {
if ($opcb !== null) {
$opcb($this);
}
}
}
}
if (sizeof($channels)) {
$this->sendCommand($name, $channels, $opcb);
}
} elseif ($name === 'PSUBSCRIBE') {
$this->subscribed();
$channels = [];
foreach ($args as $arg) {
if (!is_array($arg)) {
$arg = [$arg];
}
foreach ($arg as $chan) {
$b = !isset($this->psubscribeCb[$chan]);
CallbackWrapper::addToArray($this->psubscribeCb[$chan], $cb);
if ($b) {
$channels[] = $chan;
} else {
if ($opcb !== null) {
$opcb($this);
}
}
}
}
if (sizeof($channels)) {
$this->sendCommand($name, $channels, $opcb);
}
} elseif ($name === 'UNSUBSCRIBE') {
$channels = [];
foreach ($args as $arg) {
if (!is_array($arg)) {
$arg = [$arg];
}
foreach ($arg as $chan) {
if (!isset($this->subscribeCb[$chan])) {
if ($opcb !== null) {
$opcb($this);
}
return;
}
CallbackWrapper::removeFromArray($this->subscribeCb[$chan], $cb);
if (sizeof($this->subscribeCb[$chan]) === 0) {
$channels[] = $chan;
unset($this->subscribeCb[$chan]);
} else {
if ($opcb !== null) {
$opcb($this);
}
}
}
}
if (sizeof($channels)) {
$this->sendCommand($name, $channels, $opcb);
}
} elseif ($name === 'UNSUBSCRIBEREAL') {
/* Race-condition-free UNSUBSCRIBE */
$old = $this->subscribeCb;
$this->sendCommand('UNSUBSCRIBE', $args, function ($redis) use($cb, $args, $old) {
if (!$redis) {
$cb($redis);
return;
}
foreach ($args as $arg) {
if (!isset($this->subscribeCb[$arg])) {
continue;
}
foreach ($old[$arg] as $oldcb) {
CallbackWrapper::removeFromArray($this->subscribeCb[$arg], $oldcb);
}
if (!sizeof($this->subscribeCb[$arg])) {
unset($this->subscribeCb[$arg]);
}
}
if ($cb !== null) {
$cb($this);
}
});
} elseif ($name === 'PUNSUBSCRIBE') {
$channels = [];
foreach ($args as $arg) {
if (!is_array($arg)) {
$arg = [$arg];
}
foreach ($arg as $chan) {
CallbackWrapper::removeFromArray($this->psubscribeCb[$chan], $cb);
if (sizeof($this->psubscribeCb[$chan]) === 0) {
$channels[] = $chan;
unset($this->psubscribeCb[$chan]);
} else {
if ($opcb !== null) {
$opcb($this);
}
}
}
}
if (sizeof($channels)) {
$this->sendCommand($name, $channels, $opcb);
}
} elseif ($name === 'PUNSUBSCRIBEREAL') {
/* Race-condition-free PUNSUBSCRIBE */
$old = $this->psubscribeCb;
$this->sendCommand('PUNSUBSCRIBE', $args, function ($redis) use($cb, $args, $old) {
if (!$redis) {
$cb($redis);
return;
}
foreach ($args as $arg) {
if (!isset($this->psubscribeCb[$arg])) {
continue;
}
foreach ($old[$arg] as $oldcb) {
CallbackWrapper::removeFromArray($this->psubscribeCb[$arg], $oldcb);
}
if (!sizeof($this->psubscribeCb[$arg])) {
unset($this->psubscribeCb[$arg]);
}
}
if ($cb !== null) {
$cb($this);
}
});
} else {
if ($name === 'MGET') {
$this->resultTypeStack->push(static::RESULT_TYPE_ARGSVALS);
$this->argsStack->push($args);
} elseif ($name === 'HMGET') {
$this->resultTypeStack->push(static::RESULT_TYPE_ARGSVALS);
$a = $args;
array_shift($a);
$this->argsStack->push($a);
} elseif ($name === 'HMSET') {
if (sizeof($args) === 2) {
if (is_array($args[1])) {
$newArgs = [$args[0]];
foreach ($args[1] as $key => $value) {
$newArgs[] = $key;
$newArgs[] = $value;
}
$args = $newArgs;
}
}
} elseif ($name === 'HGETALL') {
$this->resultTypeStack->push(static::RESULT_TYPE_ASSOC);
} elseif (($name === 'ZRANGE' || $name === 'ZRANGEBYSCORE' || $name === 'ZREVRANGE' || $name === 'ZREVRANGEBYSCORE') && preg_grep('/WITHSCORES/i', $args)) {
$this->resultTypeStack->push(static::RESULT_TYPE_ASSOC);
} else {
$this->resultTypeStack->push(static::RESULT_TYPE_DEFAULT);
}
$this->sendCommand($name, $args, $cb);
if ($name === 'EXEC' || $name === 'DISCARD') {
$this->release();
}
}
}