<?php
class RetryCatch {
protected static $_currentRetries = 0;
/**
* Resets the retries counter
* @return void
*/
public static function resetRetries() {
static::$_currentRetries = 0;
}
/**
* Emulates a try-catch-retry block for each element of a provided array.
* At least two callback functions must be provided. The first one is applied
* to each element of the array. If it throws an Exception, the second callback
* is invoked and it tries to "fix" the error. This handler is called a maximum
* of $maxRetries times, before throwing another Exception itself.
* That's why the handleException callback must call resetRetries() in order
* to reset the counter back to 0 retries.
*
* Obligations of the iterateCallback:
* - It must accept the current element as a first argument
*
* Obligations of the handleExceptionCallback:
* - It must accept the Exception object as a first argument
* - It must accept the remaining array of objects as a second argument
* - It must call RetryCatch::resetRetries() upon successful error handling
*
* EXAMPLE USAGE:
* $arr = array(
* 1, false, 2, 3
* );
* RetryCatch::retry($arr, 5, 'SomeClass::iterateMethod', 'SomeClass::handleException');
*
* OR with the optional parameters, allowing the use of objects and/or
* arbitrary callback parameterrs:
* $foo = new Foo();
* RetryCatch::retry($arr, 5, 'bar', 'handle', array(1, 2, 3), array(1, 2, 3), $foo, $foo);
*
* @internal call resetRetries() if the handleCallback runs successfully
* @param array $array
* @param int $maxRetries
* @param string $iterateCallback
* @param string $handleCallback
* @param array $iterateParams
* @param array $handleParams
* @param object $iterateCallbackObject
* @param object $handleCallbackObject
* @throws RetryCatchException
*/
public static function retry($array, $maxRetries, $iterateCallback, $handleCallback, $iterateParams = null, $handleParams = null, $iterateCallbackObject = null, $handleCallbackObject = null) {
while (!empty($array)) {
reset($array);
$key = key($array);
try {
if (!is_object($iterateCallbackObject)) {
if (is_array($iterateParams) && !empty($iterateParams)) {
$useIterateParams = $iterateParams;
array_unshift($useIterateParams, $array[$key]);
call_user_func_array($iterateCallback, $useIterateParams);
} else {
call_user_func($iterateCallback, ($array[$key]));
}
} else {
if (is_array($iterateParams) && !empty($iterateParams)) {
$useIterateParams = $iterateParams;
array_unshift($useIterateParams, $array[$key]);
call_user_func_array(array($iterateCallbackObject, $iterateCallback), $useIterateParams);
} else {
$iterateCallbackObject->$iterateCallback($array[$key]);
}
}
unset($array[$key]);
} catch (Exception $e) {
static::$_currentRetries++;
if (static::$_currentRetries <= $maxRetries) {
if (!is_object($handleCallbackObject)) {
if (is_array($handleParams) && !empty($handleParams)) {
$useHandleParams = $handleParams;
array_unshift($useHandleParams, $e, $array);
call_user_func_array($handleCallback, $useHandleParams);
} else {
call_user_func($handleCallback, $e, $array);
}
} else {
if (is_array($handleParams) && !empty($handleParams)) {
$useHandleParams = $handleParams;
array_unshift($useHandleParams, $e, $array);
call_user_func_array(array($handleCallbackObject, $handleCallback), $useHandleParams);
} else {
$handleCallbackObject->$handleCallback($e, $array);
}
}
} else {
throw new RetryCatchException('RetryCatch::maxRetries reached');
}
}
}
}
}
class RetryCatchException extends Exception {}