You can, but I will warn: many consider this method quite evil.
// //stackoverflow.com/a/66377817/578023
function is_same[&$a, &$b]: bool {
$_ = [ &$a, &$b ];
return
\ReflectionReference::fromArrayElement[$_, 0]->getId[] ===
\ReflectionReference::fromArrayElement[$_, 1]->getId[];
}
function attempt_risky_action[$collection]{
$cursor=NULL;
$resuming = false;
resume:
try{
foreach[$collection as $item]{
if[$resuming && !is_same[$cursor,$item] ]{
continue; // some things have better ways to skip ahead, especially an array index
}
else {
$resuming = false;
$cursor=&$item; // main concept is to remember where you are in the iteration
} // in some situation you may have to use references, &item
// your normal loop here
.
.
.
}
} catch[ Exception $e]{
$resuming = repair_something[$e, $collection]; // returns false if your repair ran out of ideas
if[$resuming]
goto resume;
}
unset[$cursor];
}
Ideally it would be best to wrap the unset[$cursor];
call in a finally{}
block, but frankly I'm not sure how that plays with goto off hand.
If it executes because goto broke the flow then you will need some conditional logic, so the cursor still exists. If you have a return statement inside the loop you must use a finally block for call to unset[$cursor]
-- or cause a memory leak.
Then
again, while less exciting, you can do this same trick by just nesting your whole loop in do{ try/catch } while[$resuming]
. While that is not LITERALLY reversing your execution, it does exactly the same effect without risking a goto.
is_same[]
from //stackoverflow.com/a/66377817/578023
function attempt_risky_action[$collection]{
$cursor=NULL;
$resuming = false;
do{
try{
foreach[$collection as $item]{
if[$resuming && !is_same[$cursor,$item] ]{
continue;
}
else {
$resuming = false;
$cursor=&$item;
}
// your loop here
}
} catch[ Exception $e]{
$resuming = repair_something[$e, $collection]; // returns false if your repair ran out of ideas
}
finally{
if[!$resuming]{
unset[$cursor];
}
}
} while[$resuming];
}
A last method, not pictured; you can use PHP's reset[]
, prev[]
, current[]
, next[]
, end[]
faculties
These will allow you
instead to simply have your try/catch block inside a code block that iterates as a loop would -- then use prev[]
in the catch to try again.