コード例 #1
0
 /**
  * Execute loop until *as.break()* is called
  * @param callable $func loop body callable( as )
  * @param string $label optional label to use for *as.break()* and *as.continue()* in inner loops
  */
 public function loop(callable $func, $label = null)
 {
     $this->_sanityCheck();
     $loop_state = new \StdClass();
     $loop_state->model_as = new \FutoIn\RI\AsyncSteps();
     $loop_state->inner_as = null;
     $loop_state->outer_as = null;
     $loop_state->func = $func;
     $loop_state->label = $label;
     $this->add(function ($outer_as) use($loop_state) {
         $loop_state->outer_as = $outer_as;
         $create_iteration = function () use($outer_as, $loop_state) {
             $inner_as = new \FutoIn\RI\AsyncSteps($outer_as->state());
             $inner_as->copyFrom($loop_state->model_as);
             $loop_state->inner_as = $inner_as;
             $inner_as->execute();
         };
         $loop_state->model_as->add(function ($as) use($loop_state) {
             $func = $loop_state->func;
             $func($as);
         }, function ($as, $err) use($loop_state) {
             if ($err === \FutoIn\Error::LoopCont) {
                 $label = $loop_state->label;
                 $term_label = $as->state()->_loop_term_label;
                 if ($term_label && $term_label !== $label) {
                     // Unroll loops continue
                     \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) {
                         try {
                             $loop_state->outer_as->continueLoop($term_label);
                         } catch (\Exception $e) {
                         }
                     });
                 } else {
                     $as->success();
                     return;
                 }
             } elseif ($err === \FutoIn\Error::LoopBreak) {
                 $label = $loop_state->label;
                 $term_label = $as->state()->_loop_term_label;
                 if ($term_label && $term_label !== $label) {
                     // Unroll loops and break
                     \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) {
                         try {
                             $loop_state->outer_as->breakLoop($term_label);
                         } catch (\Exception $e) {
                         }
                     });
                 } else {
                     // Continue linear execution
                     \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) {
                         try {
                             $loop_state->outer_as->success();
                         } catch (\Exception $e) {
                         }
                     });
                 }
             } else {
                 \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $err) {
                     try {
                         $loop_state->outer_as->error($err);
                     } catch (\Exception $e) {
                     }
                 });
             }
             $loop_state->model_as->cancel();
             $loop_state->model_as = null;
             $loop_state->func = null;
         })->add(function ($as) use($create_iteration) {
             \FutoIn\RI\AsyncTool::callLater($create_iteration);
         });
         $outer_as->setCancel(function ($as) use($loop_state) {
             $loop_state->inner_as->cancel();
             $loop_state->inner_as = null;
             if ($loop_state->model_as) {
                 $loop_state->model_as->cancel();
                 $loop_state->model_as = null;
             }
             $loop_state->func = null;
         });
         $create_iteration();
     });
     return $this;
 }