ConfigurableCallable
Creates a callable instance with configurable behavior.
Primarily used when you need to continuously call a method or function until certain conditions are met. For example until an exception isn't being thrown, or a specific value is returned.
In this example you want to insert a row into the database, which may lead to a DeadLockException being thrown. The recommended action for dead locks is retrying the query. We use a ConfigurableCallable instance to keep trying the query until it succeeds.
// Establish a link to the database, and create a callable wrapping the
// mysqli_query() function.
$link = mysqli_connect("localhost", "my_user", "my_password", "my_db");
$query = new ConfigurableCallable("mysqli_query");
// The retryOnException(DeadLockException:class) call tells $query to keep calling
// mysqli_query($link, "INSERT INTO `members` ('headzoo')") until DeadLockException
// is no longer being thrown. As many times as needed, or until the $query->max_retries
// (defaults to 10) value is reached.
$query->retryOnException(DeadLockException::class);
$result = $query($link, "INSERT INTO `members` ('headzoo')");
In this example we will call a remote web API, which sometimes takes a few tries depending on how busy the remote server is at the any given moment. The remote server may return an empty value (null), the API library may thrown an exception, or PHP may trigger an error.
$api = new RemoteApi();
$members = new ConfigurableCallable([$api, "getMembers"]);
// When calling retryOnException() without the name of a specified exception,
// the callable will keep retrying when any kind of exception is thrown.
$members->retryOnException()
->retryOnError()
->retryOnNull();
// The $members instance will keep trying to call $api->getMembers(0, 10) until
// an exception is no longer being thrown, PHP is not triggering any errors,
// and the remote server is not returning null.
$rows = $members(0, 10);
The ConfigurableCallable::setMaxRetries() method is used to limit the number of times before the callable gives up. If the callable does give up, it will return the last value returned by the wrapped function, or throw the last exception thrown by the function. PHP errors are converted to exceptions and thrown. Errors can be logged by passing a psr\Log\LoggerInterface instance to the ConfigurableCallable constructor.
$link = mysqli_connect("localhost", "my_user", "my_password", "my_db");
$query = new ConfigurableCallable("mysqli_query", new FileLogger());
$query->retryOnException(DeadLockException::class);
$query->setMaxRetries(5);
// The $query instance will throw the last caught DeadLockException if the
// max retries value is reached without successfully inserting the row.
try {
$result = $query($link, "INSERT INTO `members` ('headzoo')");
} catch (DeadLockException $e) {
die("Could not insert row.");
}
There are dozens of different configuration options, which are listed below. In this example we keep calling a function until it returns a value greater than 42. We'll pass -1 to the setMaxRetries() method, which means retry an unlimited number of times.
$counter = ConfigurableCallable::factory(function() {
static $count = 0;
return ++$count;
});
$counter->setMaxRetries(-1)
->retryOnLessThan(42);
echo $counter();
// Outputs: 42
In addition to the retry conditions, there are also return conditions, and throw conditions. In this example we want to call a remote API until it returns true or false.
$api = new RemoteApi();
$members = new ConfigurableCallable([$api, "doesMemberExist"]);
$members->returnOnTrue()
->returnOnFalse();
$does_exist = $members("headzoo");
Sets the max number of retries.
$counter = ConfigurableCallable::factory(function() {
static $count = 0;
return ++$count;
});
$counter->setMaxRetries(-1)
->retryOnLessThan(42);
echo $counter();
// Outputs: 42
Sets a return value filter.
$func = ConfigurableCallable::factory(function() {
return "hello world!";
});
$func->setFilter(function($str) {
return strtoupper($str);
});
echo $func();
// Outputs: "HELLO WORLD!"
Retry the function until an exception is not being thrown.
$callable = ConfigurableCallable::factory("myFunction");
// To retry when a specific exception is thrown.
$callable->retryOnException(LogicException::class);
// To retry when any exception is thrown.
$callable->retryOnExcpetion();
$callable();
Return from the function when an exception is thrown.
$callable = ConfigurableCallable::factory("myFunction");
// To return when a specific exception is thrown.
$callable->returnOnException(LogicException::class);
// To return when any exception is thrown.
$callable->returnOnExcpetion();
$callable();
Throw any exception thrown by the function.
$callable = ConfigurableCallable::factory("myFunction");
// To re-throw a specific exception.
$callable->throwOnException(LogicException::class);
// To re-throw any exception.
$callable->throwOnException();
$callable();
Retry the function until no errors are triggered.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnError();
$callable();
Return from the function when an error is triggered.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnError();
$callable();
Throw an exception when the function triggers an error.
$callable = ConfigurableCallable::factory("myFunction");
$callable->throwOnError();
$callable();
Retry the function when it returns true.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnTrue();
$callable();
Return from the function when it returns true.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnTrue();
$callable();
Retry the function when it returns false.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnFalse();
$callable();
Return from the function when it returns false.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnFalse();
$callable();
Retry the function when it returns null.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnNull();
$callable();
Return from the function when it returns null.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnNull();
$callable();
Retry the function when it returns a specific type of object.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnInstanceOf(SomeClass::class);
$callable();
Return from the function when it returns a specific type of object.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnInstanceOf(SomeClass::class);
$callable();
Retry the function when the return value equals a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnEquals(42);
$callable();
Return from the function when the return value equals a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnEquals(42);
$callable();
Retry the function when the return value does not equal a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnNotEquals(42);
$callable();
Return from the function when the return value does not equal a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnNotEquals(42);
$callable();
Retry the function when the return value is greater than a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnGreaterThan(42);
$callable();
Return from the function when the return value is greater than a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnGreaterThan(42);
$callable();
Retry the function when the return value is greater than or equal to a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnGreaterThanOrEquals(42);
$callable();
Return from the function when the return value is greater than or equal to a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnGreaterThanOrEquals(42);
$callable();
Retry the function when the return value is less than a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnLessThan(42);
$callable();
Return from the function when the return value is less than a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnLessThan(42);
$callable();
Retry the function when the return value is less than or equal to a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnLessThanOrEquals(42);
$callable();
Return from the function when the return value is less than or equal to a specific value.
$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnLessThanOrEquals(42);
$callable();