Skip to content

Commit

Permalink
Add new public callAsync() method
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed Dec 28, 2024
1 parent 194370d commit e89ae33
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 13 deletions.
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ It enables you to set and query its data or use its PubSub topics to react to in
* [RedisClient](#redisclient)
* [__construct()](#__construct)
* [__call()](#__call)
* [callAsync()](#callasync)
* [end()](#end)
* [close()](#close)
* [error event](#error-event)
Expand Down Expand Up @@ -124,7 +125,8 @@ Each method call matches the respective [Redis command](https://redis.io/command
For example, the `$redis->get()` method will invoke the [`GET` command](https://redis.io/commands/get).

All [Redis commands](https://redis.io/commands) are automatically available as
public methods via the magic [`__call()` method](#__call).
public methods via the magic [`__call()` method](#__call) or through the more
explicit [`callAsync()` method].
Listing all available commands is out of scope here, please refer to the
[Redis command reference](https://redis.io/commands).

Expand Down Expand Up @@ -432,6 +434,8 @@ $redis->get($key)->then(function (?string $value) {

All [Redis commands](https://redis.io/commands) are automatically available as
public methods via this magic `__call()` method.
Note that some static analysis tools may not understand this magic method, so
you may also the [`callAsync()` method](#callasync) as a more explicit alternative.
Listing all available commands is out of scope here, please refer to the
[Redis command reference](https://redis.io/commands).

Expand All @@ -445,6 +449,43 @@ Each of these commands supports async operation and returns a [Promise](#promise
that eventually *fulfills* with its *results* on success or *rejects* with an
`Exception` on error. See also [promises](#promises) for more details.

#### callAsync()

The `callAsync(string $command, string ...$args): PromiseInterface<mixed>` method can be used to
invoke a Redis command.

```php
$redis->callAsync('GET', 'name')->then(function (?string $name): void {
echo 'Name: ' . ($name ?? 'Unknown') . PHP_EOL;
}, function (Throwable $e): void {
echo 'Error: ' . $e->getMessage() . PHP_EOL;
});
```

The `string $command` parameter can be any valid Redis command. All
[Redis commands](https://redis.io/commands/) are available through this
method. As an alternative, you may also use the magic
[`__call()` method](#__call), but note that not all static analysis tools
may understand this magic method. Listing all available commands is out
of scope here, please refer to the
[Redis command reference](https://redis.io/commands).

The optional `string ...$args` parameter can be used to pass any
additional arguments to the Redis command. Some commands may require or
support additional arguments that this method will simply forward as is.
Internally, Redis requires all arguments to be coerced to `string` values,
but you may also rely on PHP's type-juggling semantics and pass `int` or
`float` values:

```php
$redis->callAsync('SET', 'name', 'Alice', 'EX', 600);
```

This method supports async operation and returns a [Promise](#promises)
that eventually *fulfills* with its *results* on success or *rejects*
with an `Exception` on error. See also [promises](#promises) for more
details.

#### end()

The `end():void` method can be used to
Expand Down
16 changes: 8 additions & 8 deletions examples/cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@
return;
}

$params = explode(' ', $line);
$method = array_shift($params);

assert(is_callable([$redis, $method]));
$promise = $redis->$method(...$params);
$args = explode(' ', $line);
$command = strtolower(array_shift($args));

// special method such as end() / close() called
if (!$promise instanceof React\Promise\PromiseInterface) {
if (in_array($command, ['end', 'close'])) {
$redis->$command();
return;
}

$promise->then(function ($data) {
$promise = $redis->callAsync($command, ...$args);

$promise->then(function ($data): void {
echo '# reply: ' . json_encode($data) . PHP_EOL;
}, function ($e) {
}, function (Throwable $e): void {
echo '# error reply: ' . $e->getMessage() . PHP_EOL;
});
});
Expand Down
57 changes: 53 additions & 4 deletions src/RedisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,16 +160,65 @@ private function client(): PromiseInterface
}

/**
* Invoke the given command and return a Promise that will be resolved when the request has been replied to
* Invoke the given command and return a Promise that will be resolved when the command has been replied to
*
* This is a magic method that will be invoked when calling any redis
* command on this instance.
* command on this instance. See also `RedisClient::callAsync()`.
*
* @param string $name
* @param string[] $args
* @return PromiseInterface<mixed>
* @see self::callAsync()
*/
public function __call(string $name, array $args): PromiseInterface
{
return $this->callAsync($name, ...$args);
}

/**
* Invoke a Redis command.
*
* For example, the [`GET` command](https://redis.io/commands/get) can be invoked
* like this:
*
* ```php
* $redis->callAsync('GET', 'name')->then(function (?string $name): void {
* echo 'Name: ' . ($name ?? 'Unknown') . PHP_EOL;
* }, function (Throwable $e): void {
* echo 'Error: ' . $e->getMessage() . PHP_EOL;
* });
* ```
*
* The `string $command` parameter can be any valid Redis command. All
* [Redis commands](https://redis.io/commands/) are available through this
* method. As an alternative, you may also use the magic
* [`__call()` method](#__call), but note that not all static analysis tools
* may understand this magic method. Listing all available commands is out
* of scope here, please refer to the
* [Redis command reference](https://redis.io/commands).
*
* The optional `string ...$args` parameter can be used to pass any
* additional arguments to the Redis command. Some commands may require or
* support additional arguments that this method will simply forward as is.
* Internally, Redis requires all arguments to be coerced to `string` values,
* but you may also rely on PHP's type-juggling semantics and pass `int` or
* `float` values:
*
* ```php
* $redis->callAsync('SET', 'name', 'Alice', 'EX', 600);
* ```
*
* This method supports async operation and returns a [Promise](#promises)
* that eventually *fulfills* with its *results* on success or *rejects*
* with an `Exception` on error. See also [promises](#promises) for more
* details.
*
* @param string $command
* @param string ...$args
* @return PromiseInterface<mixed>
* @throws void
*/
public function callAsync(string $command, string ...$args): PromiseInterface
{
if ($this->closed) {
return reject(new \RuntimeException(
Expand All @@ -178,9 +227,9 @@ public function __call(string $name, array $args): PromiseInterface
));
}

return $this->client()->then(function (StreamingClient $redis) use ($name, $args): PromiseInterface {
return $this->client()->then(function (StreamingClient $redis) use ($command, $args): PromiseInterface {
$this->awake();
return $redis->callAsync($name, ...$args)->then(
return $redis->callAsync($command, ...$args)->then(
function ($result) {
$this->idle();
return $result;
Expand Down

0 comments on commit e89ae33

Please sign in to comment.