PHPackages                             futoin/core-php-ri-asyncsteps - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. futoin/core-php-ri-asyncsteps

ActiveLibrary

futoin/core-php-ri-asyncsteps
=============================

FutoIn Core Reference Implementation for PHP - AsyncSteps

1.1.0(10y ago)1635[1 issues](https://github.com/futoin/core-php-ri-asyncsteps/issues)2Apache-2.0PHPPHP &gt;=5.6

Since Sep 7Pushed 10y ago1 watchersCompare

[ Source](https://github.com/futoin/core-php-ri-asyncsteps)[ Packagist](https://packagist.org/packages/futoin/core-php-ri-asyncsteps)[ Docs](http://futoin.org)[ RSS](/packages/futoin-core-php-ri-asyncsteps/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (5)Versions (12)Used By (2)

[![Build Status](https://camo.githubusercontent.com/97748a317e112d133d30154499136e87794143b7a6d08e084d6dbe502e7bd3f8/68747470733a2f2f7472617669732d63692e6f72672f6675746f696e2f636f72652d7068702d72692d6173796e6373746570732e737667)](https://travis-ci.org/futoin/core-php-ri-asyncsteps)

Reference implementation of:

```
FTN12: FutoIn Async API
Version: 1.7

```

Spec: [FTN12: FutoIn Async API v1.x](http://specs.futoin.org/final/preview/ftn12_async_api-1.html)

[Web Site](http://futoin.org/)

About
=====

[](#about)

Adds classical linear program flow structure to async programming supporting exceptions. error handlers, timeouts, unlimited number of sub-steps, execution parallelism and job state/context variables.

There is little benefit of using this tool in classical PHP aproach of one-request-one-execution approach. However, it is base for FutoIn Invoker and Executor implementation, which target at daemon-like execution pattern.

It should be possible to use any other async framework from AsyncSteps by using setCancel() and/or setTimeout() methods which allow step completion without success() or error() result. Specific step-associated AsyncSteps interface will be valid for success() or error() call on external event.

It also possible to use FutoIn AsyncSteps from any other event framework. Just make sure to notify external framework from the top most error handler (for errors) and last step (for success).

To minimize cost of closure creation on repetitive execution, a special feature of "model" step is available: model step is created as usual, but must never get executed. It possible to copy steps and state variables using AsyncSteps#copyFrom() to a newly created object.

Installation
============

[](#installation)

Command line:

```
$ composer require 'futoin/core-php-ri-asyncsteps'
```

and/or composer.json:

```
    "require" : {
        "futoin/core-php-ri-asyncsteps" : "^1.1",
    }

```

Concept
=======

[](#concept)

*NOTE: copy&amp;paste from [FTN12: FutoIn Async API v1.x](http://specs.futoin.org/final/preview/ftn12_async_api-1.html)*

This interface was born as a secondary option for executor concept. However, it quickly became clear that async/reactor/proactor/light threads/etc. should be base for scalable high performance server implementations, even though it is more difficult for understanding and/or debugging. Traditional synchronous program flow becomes an addon on top of asynchronous base for legacy code and/or too complex logic.

Program flow is split into non-blocking execution steps, represented with execution callback function. Processing Unit (eg. CPU) halting/ spinning/switching-to-another-task is seen as a blocking action in program flow.

Any step must not call any of blocking functions, except for synchronization with guaranteed minimal period of lock acquisition. *Note: under minimal period, it is assumed that any acquired lock is immediately released after action with O(1) complexity and no delay caused by programmatic suspension/locking of executing task*

Every step is executed sequentially. Success result of any step becomes input for the following step.

Each step can have own error handler. Error handler is called, if AsyncSteps.error() is called within step execution or any of its sub-steps. Typical behavior is to ignore error and continue or to make cleanup actions and complete job with error.

Each step can have own sequence of sub-steps. Sub-steps can be added only during that step execution. Sub-step sequence is executed after current step execution is finished.

If there are any sub-steps added then current step must not call AsyncSteps.success() or AsyncSteps.error(). Otherwise, InternalError is raised.

It is possible to create a special "parallel" sub-step and add independent sub-steps to it. Execution of each parallel sub-step is started all together. Parallel step completes with success when all sub-steps complete with success. If error is raised in any sub-step of parallel step then all other sub-steps are canceled.

Out-of-order cancel of execution can occur by timeout, execution control engine decision (e.g. Invoker disconnect) or failure of sibling parallel step. Each step can install custom on-cancel handler to free resources and/or cancel external jobs. After cancel, it must be safe to destroy AsyncSteps object.

AsyncSteps must be used in Executor request processing. The same \[root\] AsyncSteps object must be used for all asynchronous tasks within given request processing.

AsyncSteps may be used by Invoker implementation.

AsyncSteps must support derived classes in implementation-defined way. Typical use case: functionality extension (e.g. request processing API).

For performance reasons, it is not economical to initialize AsyncSteps with business logic every time. Every implementation must support platform-specific AsyncSteps cloning/duplicating.

1.1. Levels
-----------

[](#11-levels)

When AsyncSteps (or derived) object is created all steps are added sequentially in Level 0 through add() and/or parallel(). Note: each parallel() is seen as a step.

After AsyncSteps execution is initiated, each step of Level 0 is executed. All sub-steps are added in Level n+1. Example:

```
add() -> Level 0 #1
    add() -> Level 1 #1
        add() -> Level 2 #1
        parallel() -> Level 2 #2
        add() -> Level 2 #3
    parallel() -> Level 1 #2
    add() -> Level 1 #3
parallel() -> Level 0 #2
add() -> Level 0 #3

```

Execution cannot continue to the next step of current Level until all steps of higher Level are executed.

The execution sequence would be:

```
Level 0 add #1
Level 1 add #1
Level 2 add #1
Level 2 parallel #2
Level 2 add #3
Level 1 parallel #2
Level 1 add #3
Level 0 parallel #2
Level 0 add #3

```

1.2. Error handling
-------------------

[](#12-error-handling)

Due to not linear programming, classic try/catch blocks are converted into execute/onerror. Each added step may have custom error handler. If error handler is not specified then control passed to lower Level error handler. If non is defined then execution is aborted.

Example:

```
add( -> Level 0
    func( as ){
        print( "Level 0 func" )
        add( -> Level 1
            func( as ){
                print( "Level 1 func" )
                as.error( "myerror" )
            },
            onerror( as, error ){
                print( "Level 1 onerror: " + error )
                as.error( "newerror" )
            }
        )
    },
    onerror( as, error ){
        print( "Level 0 onerror: " + error )
        as.success( "Prm" )
    }
)
add( -> Level 0
    func( as, param ){
        print( "Level 0 func2: " + param )
        as.success()
    }
)

```

Output would be:

```
Level 0 func
Level 1 func
Level 1 onerror: myerror
Level 0 onerror: newerror
Level 0 func2: Prm

```

In synchronous way, it would look like:

```
variable = null

try
{
    print( "Level 0 func" )

    try
    {
        print( "Level 1 func" )
        throw "myerror"
    }
    catch ( error )
    {
        print( "Level 1 onerror: " + error )
        throw "newerror"
    }
}
catch( error )
{
    print( "Level 0 onerror: " + error )
    variable = "Prm"
}

print( "Level 0 func2: " + variable )

```

1.3. Wait for external resources
--------------------------------

[](#13-wait-for-external-resources)

Very often, execution of step cannot continue without waiting for external event like input from network or disk. It is forbidden to block execution in event waiting. As a solution, there are special setTimeout() and setCancel() methods.

Example:

```
add(
    func( as ){
        socket.read( function( data ){
            as.success( data )
        } )

        as.setCancel( function(){
            socket.cancel_read()
        } )

        as.setTimeout( 30_000 ) // 30 seconds
    },
    onerror( as, error ){
        if ( error == timeout ) {
            print( "Timeout" )
        }
        else
        {
            print( "Read Error" )
        }
    }
)

```

1.4. Parallel execution abort
-----------------------------

[](#14-parallel-execution-abort)

Definition of parallel steps makes no sense to continue execution if any of steps fails. To avoid excessive time and resources spent on other steps, there is a concept of canceling execution similar to timeout above.

Example:

```
as.parallel()
    .add(
        func( as ){
            as.setCancel( function(){ ... } )

            // do parallel job #1
            as.state()->result1 = ...;
        }
    )
    .add(
        func( as ){
            as.setCancel( function(){ ... } )

            // do parallel job #1
            as.state()->result2 = ...;
        }
    )
    .add(
        func( as ){
            as.error( "Some Error" )
        }
    )
as.add(
    func( as ){
        print( as.state()->result1 + as.state->result2 )
        as.success()
    }
)

```

1.5. AsyncSteps cloning
-----------------------

[](#15-asyncsteps-cloning)

In long living applications the same business logic may be re-used multiple times during execution.

In a REST API server example, complex business logic can be defined only once and stored in a kind of AsyncSteps object repository. On each request, a reference object from the repository would be copied for actual processing with minimal overhead.

However, there would be no performance difference in sub-step definition unless its callback function is also created at initialization time, but not at parent step execution time (the default concept). So, it should be possible to predefine those as well and copy/inherit during step execution. Copying steps must also involve copying of state variables.

Example:

```
AsyncSteps req_repo_common;
req_repo_common.add(func( as ){
    as.add( func( as ){ ... } );
    as.copyFrom( as.state().business_logic );
    as.add( func( as ){ ... } );
});

AsyncSteps req_repo_buslog1;
req_repo_buslog1
    .add(func( as ){ ... })
    .add(func( as ){ ... });

AsyncSteps actual_exec = copy req_repo_common;
actual_exec.state().business_logic = req_repo_buslog1;
actual_exec.execute();

```

However, this approach only make sense for deep performance optimizations.

1.6. Implicit as.success()
--------------------------

[](#16-implicit-assuccess)

If there are no sub-steps added, no timeout set and no cancel handler set then implicit as.success() call is assumed to simplify code and increase efficiency.

```
as.add(func( as ){
    doSomeStuff( as );
})

```

1.7. Error Info and Last Exception
----------------------------------

[](#17-error-info-and-last-exception)

Pre-defined state variables:

- **error\_info** - value of the second parameter passed to the last *as.error()* call
- **last\_exception** - the last exception caught, if feasible

Error code is not always descriptive enough, especially, if it can be generated in multiple ways. As a convention special "error\_info" state field should hold descriptive information of the last error. Therefore, *as.error()* is extended with optional parameter error\_info.

"last\_exception" state variables may hold the last exception object caught, if feasible to implement. It should be populated with FutoIn errors as well.

1.8. Async Loops
----------------

[](#18-async-loops)

Almost always, async program flow is not linear. Sometimes, loops are required.

Basic principals of async loops:

```
    as.loop( func( as ){
        call_some_library( as );
        as.add( func( as, result ){
            if ( !result )
            {
                // exit loop
                as.break();
            }
        } );
    } )

```

Inner loops and identifiers:

```
    // start loop
    as.loop(
        func( as ){
            as.loop( func( as ){
                call_some_library( as );
                as.add( func( as, result ){
                    if ( !result )
                    {
                        // exit loop
                        as.continue( "OUTER" );
                    }

                    as.success( result );
                } );
            } );

            as.add( func( as, result ){
                // use it somehow
                as.success();
            } );
        },
        "OUTER"
    )

```

Loop n times.

```
    as.repeat( 3, func( as, i ){
        print( 'Iteration: ' + i )
    } )

```

Traverse through list or map:

```
    as.forEach(
        [ 'apple', 'banana' ],
        func( as, k, v ){
            print( k + " = " + v )
        }
    )

```

### 1.8.1. Termination

[](#181-termination)

Normal loop termination is performed either by loop condition (e.g. as.forEach(), as.repeat()) or by as.break() call. Normal termination is seen as as.success() call.

Abnormal termination is possible through as.error(), including timeout, or external as.cancel(). Abnormal termination is seen as as.error() call.

1.9. The Safety Rules of libraries with AsyncSteps interface
------------------------------------------------------------

[](#19-the-safety-rules-of-libraries-with-asyncsteps-interface)

1. as.success() should be called only in top-most function of the step (the one passed to as.add() directly)
2. setCancel() and/or setTimeout() must be called only in top most function as repeated call overrides in scope of step

1.10. Reserved keyword name clash
---------------------------------

[](#110-reserved-keyword-name-clash)

If any of API identifiers clashes with reserved word or has illegal symbols then implementation-defined name mangling is allowed, but with the following guidelines in priority.

Pre-defined alternative method names, if the default matches language-specific reserved keywords:

- *loop* -&gt; makeLoop
- *forEach* -&gt; loopForEach
- *repeat* -&gt; repeatLoop
- *break* -&gt; breakLoop
- *continue* -&gt; continueLoop
- Otherwise, - try adding underscore to the end of the identifier (e.g. do -&gt; do\_)

Examples
========

[](#examples)

Simple steps
------------

[](#simple-steps)

```
use \FutoIn\RI\AsyncSteps;
use \FutoIn\RI\ScopedSteps;

$root_as = new ScopedSteps();

$root_as->add(
    function( $as ){
        $as->success( "MyValue" );
    }
)->add(
    function( $as, $arg ){
        if ( $arg === 'MyValue' )
        {
            $as->add( function( $as ){
                $as->error( 'MyError', 'Something bad has happened' );
            });
        }

        $as->successStep();
    },
    function( $as, $err )
    {
        if ( $err === 'MyError' )
        {
            $as->success( 'NotSoBad' );
        }
    }
);

$root_as->add(
    function( $as, $arg )
    {
        if ( $arg === 'NotSoBad' )
        {
            echo 'MyError was ignored: ' . $as->state()->error_info . PHP_EOL;
        }

        $as->state()->p1arg = 'abc';
        $as->state()->p2arg = 'xyz';

        $p = $as->parallel();

        $p->add( function( $as ){
            echo 'Parallel Step 1' . PHP_EOL;

            $as->add( function( $as ){
                echo 'Parallel Step 1->1' . PHP_EOL;
                $as->p1 = $as->p1arg . '1';
                $as->success();
            } );
        } )
        ->add( function( $as ){
            echo 'Parallel Step 2' . PHP_EOL;

            $as->add( function( $as ){
                echo 'Parallel Step 2->1' . PHP_EOL;
                $as->p2 = $as->p2arg . '2';
                $as->success();
            } );
        } );
    }
)->add( function( $as ){
    echo 'Parallel 1 result: ' . $as->state()->p1 . PHP_EOL;
    echo 'Parallel 2 result: ' . $as->p2 . PHP_EOL;
} );

// Note: we use ScopedSteps instead of AsyncSteps in this example
//$root_as->execute();
$root_as->run();
```

Result:

```
MyError was ignored: Something bad has happened
Parallel Step 1
Parallel Step 2
Parallel Step 1->1
Parallel Step 2->1
Parallel 1 result: abc1
Parallel 2 result: xyz2

```

External event wait
-------------------

[](#external-event-wait)

```
use \FutoIn\RI\AsyncSteps;
use \FutoIn\RI\ScopedSteps;
use \FutoIn\RI\AsyncTool;

function dummy_service_read( $success, $error ){
    // We expect it calles success when data is available
    // and error, if error occurs
    // Returns some request handle
    return null;
}

function dummy_service_cancel( $reqhandle ){
    // We assume it cancels previously scheduled reqhandle
}

$root_as = new ScopedSteps();

$root_as->add( function( $as ){
    AsyncTool::callLater( function() use ( $as ) {
        $as->success( 'async success()' );
    } );

    $as->setTimeout( 10 ); // ms
} )->add(
    function( $as, $arg ){
        echo $arg . PHP_EOL;

        $reqhandle = dummy_service_read(
            function( $data ) use ( $as ) {
                $as->success( $data );
            },
            function( $err ) use ( $as ) {
                if ( $err !== 'SomeSpecificCancelCode' )
                {
                    $as->error( $err );
                }
            }
        );

        $as->setCancel(function($as) use ( $reqhandle ) {
            dummy_service_cancel( $reqhandle );
        });

        // OPTIONAL. Set timeout of 1s
        $as->setTimeout( 1000 );
    },
    function( $as, $err )
    {
        echo $err . ": " . $as->error_info . PHP_EOL;
    }
);

// Note: we use ScopedSteps instead of AsyncSteps in this example
//$root_as->execute();
$root_as->run();
```

Result:

```
async success()
Timeout:

```

Model steps (avoid closure creation overhead on repetitive execution)
---------------------------------------------------------------------

[](#model-steps-avoid-closure-creation-overhead-on-repetitive-execution)

```
use \FutoIn\RI\AsyncSteps;
use \FutoIn\RI\AsyncToolTest;

// Note, we have no default event engine in PHP
AsyncToolTest::init();

$model_as = new AsyncSteps();
$model_as->state()->variable = 'Vanilla';

$model_as->add( function($as){
    echo '-----' . PHP_EOL;
    echo 'Hi! I am from model_as' . PHP_EOL;
    echo 'State.var: ' . $as->variable . PHP_EOL;
    $as->variable = 'Dirty';
    $as->success();
});

for ( $i = 0; $i < 3; ++$i )
{
    $root_as = new AsyncSteps();
    $root_as->copyFrom( $model_as );
    $root_as->add( function( $as ) use ( $model_as ) {
        $as->add( function( $as ){
            echo '>> The first inner step' . PHP_EOL;
            $as->success();
        });
        $as->copyFrom( $model_as );
        $as->successStep();
    });
    $root_as->execute();
}

// Process all pending events
AsyncToolTest::run();
```

Result. Please note the order as only the first step is executed in the loop. The rest is executed quasi-parallel by nature of async programming. The model\_as closure gets executed 6 times, but created only once.

```
-----
Hi! I am from model_as
State.var: Vanilla
-----
Hi! I am from model_as
State.var: Vanilla
-----
Hi! I am from model_as
State.var: Vanilla
>> The first inner step
>> The first inner step
>> The first inner step
-----
Hi! I am from model_as
State.var: Dirty
-----
Hi! I am from model_as
State.var: Dirty
-----
Hi! I am from model_as
State.var: Dirty

```

API documentation
=================

[](#api-documentation)

API Index
================================================

[](#api-index)

- FutoIn
    - FutoIn\\RI
        - FutoIn\\RI\\Details
            - [AsyncStepsProtection](#FutoIn-RI-Details-AsyncStepsProtection.md)
            - [StateObject](#FutoIn-RI-Details-StateObject.md)
            - [ParallelStep](#FutoIn-RI-Details-ParallelStep.md)
            - [AsyncToolImpl](#FutoIn-RI-Details-AsyncToolImpl.md)
        - [AsyncSteps](#FutoIn-RI-AsyncSteps.md)
        - [ScopedSteps](#FutoIn-RI-ScopedSteps.md)
        - [AsyncTool](#FutoIn-RI-AsyncTool.md)
        - [AsyncToolTest](#FutoIn-RI-AsyncToolTest.md)

FutoIn\\RI\\AsyncSteps
=========================================================================

[](#futoinriasyncsteps)

AsyncSteps reference implementation as per "FTN12: FutoIn Async API"

- Class name: AsyncSteps
- Namespace: FutoIn\\RI
- This class implements: FutoIn\\AsyncSteps

Methods
-------

[](#methods)

### \_\_construct

[](#__construct)

```
mixed FutoIn\RI\AsyncSteps::__construct(object $state)

```

Init

- Visibility: **public**

#### Arguments

[](#arguments)

- $state **object** - &lt;p&gt;for INTERNAL use only&lt;/p&gt;

### add

[](#add)

```
\FutoIn\AsyncSteps FutoIn\RI\AsyncSteps::add(callable $func, callable $onerror)

```

Add $func step executor to end of current AsyncSteps level queue

- Visibility: **public**

#### Arguments

[](#arguments-1)

- $func **callable** - &lt;p&gt;void execute\_callback( AsyncSteps as\[, previous\_success\_args\] )&lt;/p&gt;
- $onerror **callable** - &lt;p&gt;OPTIONAL: void error\_callback( AsyncSteps as, error )&lt;/p&gt;

### copyFrom

[](#copyfrom)

```
\FutoIn\AsyncSteps FutoIn\RI\AsyncSteps::copyFrom(\FutoIn\RI\AsyncSteps $other)

```

Copy steps from other AsyncSteps, useful for sub-step cloning

- Visibility: **public**

#### Arguments

[](#arguments-2)

- $other **[FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)** - &lt;p&gt;model AsyncSteps object for re-use&lt;/p&gt;

### parallel

[](#parallel)

```
\FutoIn\AsyncSteps FutoIn\RI\AsyncSteps::parallel(callable $onerror)

```

Create special object to queue steps for execution in parallel

- Visibility: **public**

#### Arguments

[](#arguments-3)

- $onerror **callable** - &lt;p&gt;OPTIONAL: void error\_callback( AsyncSteps as, error )&lt;/p&gt;

### state

[](#state)

```
\StdClass FutoIn\RI\AsyncSteps::state()

```

Access AsyncSteps state object

- Visibility: **public**

### success

[](#success)

```
mixed FutoIn\RI\AsyncSteps::success()

```

Set "success" state of current step execution

- Visibility: **public**

### successStep

[](#successstep)

```
mixed FutoIn\RI\AsyncSteps::successStep()

```

Call success() or add efficient dummy step equal to as.success() in behavior (depending on presence of other sub-steps)

- Visibility: **public**

### error

[](#error)

```
mixed FutoIn\RI\AsyncSteps::error(string $name, string $error_info)

```

Set "error" state of current step execution

- Visibility: **public**

#### Arguments

[](#arguments-4)

- $name **string** - &lt;p&gt;Type of error&lt;/p&gt;
- $error\_info **string** - &lt;p&gt;Error description to be put into "error\_info" state field&lt;/p&gt;

### setTimeout

[](#settimeout)

```
mixed FutoIn\RI\AsyncSteps::setTimeout(integer $timeout_ms)

```

Delay further execution until as.success() or as.error() is called

- Visibility: **public**

#### Arguments

[](#arguments-5)

- $timeout\_ms **integer** - &lt;p&gt;Timeout in milliseconds&lt;/p&gt;

### \_\_invoke

[](#__invoke)

```
mixed FutoIn\RI\AsyncSteps::__invoke()

```

PHP-specific alias for success()

- Visibility: **public**

### setCancel

[](#setcancel)

```
mixed FutoIn\RI\AsyncSteps::setCancel($oncancel)

```

Set cancellation callback

- Visibility: **public**

#### Arguments

[](#arguments-6)

- $oncancel **mixed** - &lt;p&gt;void cancel\_callback( AsyncSteps as ) \\note Please see the specification&lt;/p&gt;

### execute

[](#execute)

```
mixed FutoIn\RI\AsyncSteps::execute()

```

Start execution of AsyncSteps

It can be called only on root instance of AsyncSteps

- Visibility: **public**

### cancel

[](#cancel)

```
mixed FutoIn\RI\AsyncSteps::cancel()

```

Cancel execution of AsyncSteps

It can be called only on root instance of AsyncSteps

- Visibility: **public**

### loop

[](#loop)

```
mixed FutoIn\RI\AsyncSteps::loop(callable $func, string $label)

```

Execute loop until *as.break()* is called

- Visibility: **public**

#### Arguments

[](#arguments-7)

- $func **callable** - &lt;p&gt;loop body callable( as )&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### loopForEach

[](#loopforeach)

```
mixed FutoIn\RI\AsyncSteps::loopForEach(array $maplist, callable $func, string $label)

```

For each *map* or *list* element call *func( as, key, value )*

- Visibility: **public**

#### Arguments

[](#arguments-8)

- $maplist **array**
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### repeat

[](#repeat)

```
mixed FutoIn\RI\AsyncSteps::repeat(integer $count, callable $func, string $label)

```

Call *func(as, i)* for *count* times

- Visibility: **public**

#### Arguments

[](#arguments-9)

- $count **integer** - &lt;p&gt;how many times to call the &lt;em&gt;func&lt;/em&gt;&lt;/p&gt;
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### breakLoop

[](#breakloop)

```
mixed FutoIn\RI\AsyncSteps::breakLoop(string $label)

```

Break execution of current loop, throws exception

- Visibility: **public**

#### Arguments

[](#arguments-10)

- $label **string** - &lt;p&gt;unwind loops, until &lt;em&gt;label&lt;/em&gt; named loop is exited&lt;/p&gt;

### continueLoop

[](#continueloop)

```
mixed FutoIn\RI\AsyncSteps::continueLoop(string $label)

```

Ccontinue loop execution from the next iteration, throws exception

- Visibility: **public**

#### Arguments

[](#arguments-11)

- $label **string** - &lt;p&gt;break loops, until &lt;em&gt;label&lt;/em&gt; named loop is found&lt;/p&gt;

### \_\_set

[](#__set)

```
mixed FutoIn\RI\AsyncSteps::__set(string $name, mixed $value)

```

state() access through AsyncSteps interface / set value

- Visibility: **public**

#### Arguments

[](#arguments-12)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;
- $value **mixed** - &lt;p&gt;state variable value&lt;/p&gt;

### \_\_get

[](#__get)

```
mixed FutoIn\RI\AsyncSteps::__get(string $name)

```

state() access through AsyncSteps interface / get value

- Visibility: **public**

#### Arguments

[](#arguments-13)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_isset

[](#__isset)

```
boolean FutoIn\RI\AsyncSteps::__isset(string $name)

```

state() access through AsyncSteps interface / check value exists

- Visibility: **public**

#### Arguments

[](#arguments-14)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_unset

[](#__unset)

```
mixed FutoIn\RI\AsyncSteps::__unset(string $name)

```

state() access through AsyncSteps interface / delete value

- Visibility: **public**

#### Arguments

[](#arguments-15)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

FutoIn\\RI\\AsyncTool
=======================================================================

[](#futoinriasynctool)

Wrapper interface for singleton AsyncTools implementation

- Class name: AsyncTool
- Namespace: FutoIn\\RI

Methods
-------

[](#methods-1)

### init

[](#init)

```
mixed FutoIn\RI\AsyncTool::init(\FutoIn\RI\Details\AsyncToolImpl $impl)

```

Install Async Tool implementation

- Visibility: **public**
- This method is **static**.

#### Arguments

[](#arguments-16)

- $impl **[FutoIn\\RI\\Details\\AsyncToolImpl](#FutoIn-RI-Details-AsyncToolImpl.md)** - &lt;p&gt;AsyncTools implementation&lt;/p&gt;

### callLater

[](#calllater)

```
mixed FutoIn\RI\AsyncTool::callLater(callable $cb, integer $delay_ms)

```

Schedule $cb for later execution after $delays\_ms milliseconds

- Visibility: **public**
- This method is **static**.

#### Arguments

[](#arguments-17)

- $cb **callable** - &lt;p&gt;Callable to execute&lt;/p&gt;
- $delay\_ms **integer** - &lt;p&gt;Required delay in milliseconds&lt;/p&gt;

### cancelCall

[](#cancelcall)

```
boolean FutoIn\RI\AsyncTool::cancelCall(mixed $ref)

```

Cancel previously scheduled $ref item

- Visibility: **public**
- This method is **static**.

#### Arguments

[](#arguments-18)

- $ref **mixed** - &lt;p&gt;Any value returned from callLater()&lt;/p&gt;

FutoIn\\RI\\AsyncToolTest
===============================================================================

[](#futoinriasynctooltest)

Async Tool implementation for testing purposes

Install like \\FutoIn\\RI\\AsyncToolTest::init().

The primary feature is predictive event firing for debugging and Unit Testing through nextEvent()

- Class name: AsyncToolTest
- Namespace: FutoIn\\RI
- Parent class: [FutoIn\\RI\\Details\\AsyncToolImpl](#FutoIn-RI-Details-AsyncToolImpl.md)

Methods
-------

[](#methods-2)

### nextEvent

[](#nextevent)

```
mixed FutoIn\RI\AsyncToolTest::nextEvent()

```

Wait and execute the next item in queue, if any

- Visibility: **public**
- This method is **static**.

### hasEvents

[](#hasevents)

```
boolean FutoIn\RI\AsyncToolTest::hasEvents()

```

Check if any item is scheduled (for unit testing)

- Visibility: **public**
- This method is **static**.

### resetEvents

[](#resetevents)

```
mixed FutoIn\RI\AsyncToolTest::resetEvents()

```

Reset event queue (for unit testing)

- Visibility: **public**
- This method is **static**.

### getEvents

[](#getevents)

```
array FutoIn\RI\AsyncToolTest::getEvents()

```

Get internal item queue (for unit testing)

- Visibility: **public**
- This method is **static**.

### run

[](#run)

```
mixed FutoIn\RI\AsyncToolTest::run()

```

Run event loop until last event pending

- Visibility: **public**
- This method is **static**.

### \_\_construct

[](#__construct-1)

```
mixed FutoIn\RI\Details\AsyncToolImpl::__construct()

```

Any derived class should call this c-tor for future-compatibility

- Visibility: **protected**
- This method is defined by [FutoIn\\RI\\Details\\AsyncToolImpl](#FutoIn-RI-Details-AsyncToolImpl.md)

### init

[](#init-1)

```
mixed FutoIn\RI\Details\AsyncToolImpl::init()

```

Install Async Tool implementation, call using derived class

- Visibility: **public**
- This method is **static**.
- This method is defined by [FutoIn\\RI\\Details\\AsyncToolImpl](#FutoIn-RI-Details-AsyncToolImpl.md)

### callLater

[](#calllater-1)

```
mixed FutoIn\RI\Details\AsyncToolImpl::callLater(callable $cb, integer $delay_ms)

```

Schedule $cb for later execution after $delays\_ms milliseconds

- Visibility: **public**
- This method is **abstract**.
- This method is defined by [FutoIn\\RI\\Details\\AsyncToolImpl](#FutoIn-RI-Details-AsyncToolImpl.md)

#### Arguments

[](#arguments-19)

- $cb **callable** - &lt;p&gt;Callable to execute&lt;/p&gt;
- $delay\_ms **integer** - &lt;p&gt;Required delay in milliseconds&lt;/p&gt;

### cancelCall

[](#cancelcall-1)

```
mixed FutoIn\RI\Details\AsyncToolImpl::cancelCall(mixed $ref)

```

Cancel previously scheduled $ref item

- Visibility: **public**
- This method is **abstract**.
- This method is defined by [FutoIn\\RI\\Details\\AsyncToolImpl](#FutoIn-RI-Details-AsyncToolImpl.md)

#### Arguments

[](#arguments-20)

- $ref **mixed** - &lt;p&gt;Any value returned from callLater()&lt;/p&gt;

FutoIn\\RI\\Details\\AsyncStepsProtection
==============================================================================================================

[](#futoinridetailsasyncstepsprotection)

Internal class to organize AsyncSteps levels during execution

- Class name: AsyncStepsProtection
- Namespace: FutoIn\\RI\\Details
- This class implements: FutoIn\\AsyncSteps

Properties
----------

[](#properties)

### $root

[](#root)

```
private mixed $root

```

- Visibility: **private**

### $adapter\_stack

[](#adapter_stack)

```
private mixed $adapter_stack

```

- Visibility: **private**

### $\_onerror

[](#_onerror)

```
public mixed $_onerror

```

- Visibility: **public**

### $\_oncancel

[](#_oncancel)

```
public mixed $_oncancel

```

- Visibility: **public**

### $\_queue

[](#_queue)

```
public mixed $_queue = null

```

- Visibility: **public**

### $\_limit\_event

[](#_limit_event)

```
public mixed $_limit_event = null

```

- Visibility: **public**

Methods
-------

[](#methods-3)

### \_\_construct

[](#__construct-2)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::__construct($root, $adapter_stack)

```

- Visibility: **public**

#### Arguments

[](#arguments-21)

- $root **mixed**
- $adapter\_stack **mixed**

### \_cleanup

[](#_cleanup)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::_cleanup()

```

- Visibility: **public**

### \_sanityCheck

[](#_sanitycheck)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::_sanityCheck()

```

- Visibility: **private**

### add

[](#add-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::add(callable $func, callable $onerror)

```

- Visibility: **public**

#### Arguments

[](#arguments-22)

- $func **callable**
- $onerror **callable**

### parallel

[](#parallel-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::parallel(callable $onerror)

```

- Visibility: **public**

#### Arguments

[](#arguments-23)

- $onerror **callable**

### state

[](#state-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::state()

```

- Visibility: **public**

### success

[](#success-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::success()

```

- Visibility: **public**

### successStep

[](#successstep-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::successStep()

```

- Visibility: **public**

### error

[](#error-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::error($name, $error_info)

```

- Visibility: **public**

#### Arguments

[](#arguments-24)

- $name **mixed**
- $error\_info **mixed**

### setTimeout

[](#settimeout-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::setTimeout($timeout_ms)

```

- Visibility: **public**

#### Arguments

[](#arguments-25)

- $timeout\_ms **mixed**

### \_\_invoke

[](#__invoke-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::__invoke()

```

- Visibility: **public**

### setCancel

[](#setcancel-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::setCancel(callable $oncancel)

```

- Visibility: **public**

#### Arguments

[](#arguments-26)

- $oncancel **callable**

### execute

[](#execute-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::execute()

```

- Visibility: **public**

### cancel

[](#cancel-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::cancel()

```

- Visibility: **public**

### copyFrom

[](#copyfrom-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::copyFrom(\FutoIn\AsyncSteps $other)

```

- Visibility: **public**

#### Arguments

[](#arguments-27)

- $other **FutoIn\\AsyncSteps**

### \_\_clone

[](#__clone)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::__clone()

```

- Visibility: **public**

### loop

[](#loop-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::loop(callable $func, string $label)

```

Execute loop until *as.break()* is called

- Visibility: **public**

#### Arguments

[](#arguments-28)

- $func **callable** - &lt;p&gt;loop body callable( as )&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### loopForEach

[](#loopforeach-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::loopForEach(array $maplist, callable $func, string $label)

```

For each *map* or *list* element call *func( as, key, value )*

- Visibility: **public**

#### Arguments

[](#arguments-29)

- $maplist **array**
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### repeat

[](#repeat-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::repeat(integer $count, callable $func, string $label)

```

Call *func(as, i)* for *count* times

- Visibility: **public**

#### Arguments

[](#arguments-30)

- $count **integer** - &lt;p&gt;how many times to call the &lt;em&gt;func&lt;/em&gt;&lt;/p&gt;
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### breakLoop

[](#breakloop-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::breakLoop(string $label)

```

Break execution of current loop, throws exception

- Visibility: **public**

#### Arguments

[](#arguments-31)

- $label **string** - &lt;p&gt;unwind loops, until &lt;em&gt;label&lt;/em&gt; named loop is exited&lt;/p&gt;

### continueLoop

[](#continueloop-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::continueLoop(string $label)

```

Ccontinue loop execution from the next iteration, throws exception

- Visibility: **public**

#### Arguments

[](#arguments-32)

- $label **string** - &lt;p&gt;break loops, until &lt;em&gt;label&lt;/em&gt; named loop is found&lt;/p&gt;

### \_\_set

[](#__set-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::__set(string $name, mixed $value)

```

state() access through AsyncSteps interface / set value

- Visibility: **public**

#### Arguments

[](#arguments-33)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;
- $value **mixed** - &lt;p&gt;state variable value&lt;/p&gt;

### \_\_get

[](#__get-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::__get(string $name)

```

state() access through AsyncSteps interface / get value

- Visibility: **public**

#### Arguments

[](#arguments-34)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_isset

[](#__isset-1)

```
boolean FutoIn\RI\Details\AsyncStepsProtection::__isset(string $name)

```

state() access through AsyncSteps interface / check value exists

- Visibility: **public**

#### Arguments

[](#arguments-35)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_unset

[](#__unset-1)

```
mixed FutoIn\RI\Details\AsyncStepsProtection::__unset(string $name)

```

state() access through AsyncSteps interface / delete value

- Visibility: **public**

#### Arguments

[](#arguments-36)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

FutoIn\\RI\\Details\\AsyncToolImpl
================================================================================================

[](#futoinridetailsasynctoolimpl)

Abstract base for AsyncTool implementation

- Class name: AsyncToolImpl
- Namespace: FutoIn\\RI\\Details
- This is an **abstract** class

Methods
-------

[](#methods-4)

### \_\_construct

[](#__construct-3)

```
mixed FutoIn\RI\Details\AsyncToolImpl::__construct()

```

Any derived class should call this c-tor for future-compatibility

- Visibility: **protected**

### init

[](#init-2)

```
mixed FutoIn\RI\Details\AsyncToolImpl::init()

```

Install Async Tool implementation, call using derived class

- Visibility: **public**
- This method is **static**.

### callLater

[](#calllater-2)

```
mixed FutoIn\RI\Details\AsyncToolImpl::callLater(callable $cb, integer $delay_ms)

```

Schedule $cb for later execution after $delays\_ms milliseconds

- Visibility: **public**
- This method is **abstract**.

#### Arguments

[](#arguments-37)

- $cb **callable** - &lt;p&gt;Callable to execute&lt;/p&gt;
- $delay\_ms **integer** - &lt;p&gt;Required delay in milliseconds&lt;/p&gt;

### cancelCall

[](#cancelcall-2)

```
mixed FutoIn\RI\Details\AsyncToolImpl::cancelCall(mixed $ref)

```

Cancel previously scheduled $ref item

- Visibility: **public**
- This method is **abstract**.

#### Arguments

[](#arguments-38)

- $ref **mixed** - &lt;p&gt;Any value returned from callLater()&lt;/p&gt;

FutoIn\\RI\\Details\\ParallelStep
==============================================================================================

[](#futoinridetailsparallelstep)

Internal class to organize Parallel step execution

- Class name: ParallelStep
- Namespace: FutoIn\\RI\\Details
- This class implements: FutoIn\\AsyncSteps

Properties
----------

[](#properties-1)

### $root

[](#root-1)

```
private mixed $root

```

- Visibility: **private**

### $as

[](#as)

```
private mixed $as

```

- Visibility: **private**

### $parallel\_steps

[](#parallel_steps)

```
private mixed $parallel_steps

```

- Visibility: **private**

### $complete\_count

[](#complete_count)

```
private mixed $complete_count

```

- Visibility: **private**

Methods
-------

[](#methods-5)

### \_\_construct

[](#__construct-4)

```
mixed FutoIn\RI\Details\ParallelStep::__construct($root, $async_iface)

```

- Visibility: **public**

#### Arguments

[](#arguments-39)

- $root **mixed**
- $async\_iface **mixed**

### \_cleanup

[](#_cleanup-1)

```
mixed FutoIn\RI\Details\ParallelStep::_cleanup()

```

- Visibility: **private**

### add

[](#add-2)

```
mixed FutoIn\RI\Details\ParallelStep::add(callable $func, callable $onerror)

```

- Visibility: **public**

#### Arguments

[](#arguments-40)

- $func **callable**
- $onerror **callable**

### parallel

[](#parallel-2)

```
mixed FutoIn\RI\Details\ParallelStep::parallel(callable $onerror)

```

- Visibility: **public**

#### Arguments

[](#arguments-41)

- $onerror **callable**

### state

[](#state-2)

```
mixed FutoIn\RI\Details\ParallelStep::state()

```

- Visibility: **public**

### success

[](#success-2)

```
mixed FutoIn\RI\Details\ParallelStep::success()

```

- Visibility: **public**

### successStep

[](#successstep-2)

```
mixed FutoIn\RI\Details\ParallelStep::successStep()

```

- Visibility: **public**

### error

[](#error-2)

```
mixed FutoIn\RI\Details\ParallelStep::error($name, $errorinfo)

```

- Visibility: **public**

#### Arguments

[](#arguments-42)

- $name **mixed**
- $errorinfo **mixed**

### \_\_invoke

[](#__invoke-2)

```
mixed FutoIn\RI\Details\ParallelStep::__invoke()

```

- Visibility: **public**

### setTimeout

[](#settimeout-2)

```
mixed FutoIn\RI\Details\ParallelStep::setTimeout($timeout_ms)

```

- Visibility: **public**

#### Arguments

[](#arguments-43)

- $timeout\_ms **mixed**

### setCancel

[](#setcancel-2)

```
mixed FutoIn\RI\Details\ParallelStep::setCancel(callable $oncancel)

```

- Visibility: **public**

#### Arguments

[](#arguments-44)

- $oncancel **callable**

### execute

[](#execute-2)

```
mixed FutoIn\RI\Details\ParallelStep::execute()

```

- Visibility: **public**

### copyFrom

[](#copyfrom-2)

```
mixed FutoIn\RI\Details\ParallelStep::copyFrom(\FutoIn\AsyncSteps $other)

```

- Visibility: **public**

#### Arguments

[](#arguments-45)

- $other **FutoIn\\AsyncSteps**

### \_\_clone

[](#__clone-1)

```
mixed FutoIn\RI\Details\ParallelStep::__clone()

```

- Visibility: **public**

### loop

[](#loop-2)

```
mixed FutoIn\RI\Details\ParallelStep::loop(callable $func, string $label)

```

Execute loop until *as.break()* is called

- Visibility: **public**

#### Arguments

[](#arguments-46)

- $func **callable** - &lt;p&gt;loop body callable( as )&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### loopForEach

[](#loopforeach-2)

```
mixed FutoIn\RI\Details\ParallelStep::loopForEach(array $maplist, callable $func, string $label)

```

For each *map* or *list* element call *func( as, key, value )*

- Visibility: **public**

#### Arguments

[](#arguments-47)

- $maplist **array**
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### repeat

[](#repeat-2)

```
mixed FutoIn\RI\Details\ParallelStep::repeat(integer $count, callable $func, string $label)

```

Call *func(as, i)* for *count* times

- Visibility: **public**

#### Arguments

[](#arguments-48)

- $count **integer** - &lt;p&gt;how many times to call the &lt;em&gt;func&lt;/em&gt;&lt;/p&gt;
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### breakLoop

[](#breakloop-2)

```
mixed FutoIn\RI\Details\ParallelStep::breakLoop(string $label)

```

Break execution of current loop, throws exception

- Visibility: **public**

#### Arguments

[](#arguments-49)

- $label **string** - &lt;p&gt;unwind loops, until &lt;em&gt;label&lt;/em&gt; named loop is exited&lt;/p&gt;

### continueLoop

[](#continueloop-2)

```
mixed FutoIn\RI\Details\ParallelStep::continueLoop(string $label)

```

Ccontinue loop execution from the next iteration, throws exception

- Visibility: **public**

#### Arguments

[](#arguments-50)

- $label **string** - &lt;p&gt;break loops, until &lt;em&gt;label&lt;/em&gt; named loop is found&lt;/p&gt;

### \_\_set

[](#__set-2)

```
mixed FutoIn\RI\Details\ParallelStep::__set(string $name, mixed $value)

```

state() access through AsyncSteps interface / set value

- Visibility: **public**

#### Arguments

[](#arguments-51)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;
- $value **mixed** - &lt;p&gt;state variable value&lt;/p&gt;

### \_\_get

[](#__get-2)

```
mixed FutoIn\RI\Details\ParallelStep::__get(string $name)

```

state() access through AsyncSteps interface / get value

- Visibility: **public**

#### Arguments

[](#arguments-52)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_isset

[](#__isset-2)

```
boolean FutoIn\RI\Details\ParallelStep::__isset(string $name)

```

state() access through AsyncSteps interface / check value exists

- Visibility: **public**

#### Arguments

[](#arguments-53)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_unset

[](#__unset-2)

```
mixed FutoIn\RI\Details\ParallelStep::__unset(string $name)

```

state() access through AsyncSteps interface / delete value

- Visibility: **public**

#### Arguments

[](#arguments-54)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

FutoIn\\RI\\Details\\StateObject
============================================================================================

[](#futoinridetailsstateobject)

Internal class to organize state object.

- Class name: StateObject
- Namespace: FutoIn\\RI\\Details

Properties
----------

[](#properties-2)

### $error\_info

[](#error_info)

```
public mixed $error_info = null

```

- Visibility: **public**

### $last\_exception

[](#last_exception)

```
public mixed $last_exception = null

```

- Visibility: **public**

### $\_loop\_term\_label

[](#_loop_term_label)

```
public mixed $_loop_term_label = null

```

- Visibility: **public**

FutoIn\\RI\\ScopedSteps
===========================================================================

[](#futoinriscopedsteps)

Not standard API. Use for synchronous invocation of AsyncSteps, IF there is no true event loop.

Example: $s = new ScopedSteps; $s-&gt;add( ... )-&gt;add( ... ); $s-&gt;run();

\\note AsyncTool must be initialized with AsyncToolTest or not initalized at all

- Class name: ScopedSteps
- Namespace: FutoIn\\RI
- Parent class: [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

Methods
-------

[](#methods-6)

### \_\_construct

[](#__construct-5)

```
mixed FutoIn\RI\AsyncSteps::__construct(object $state)

```

Init

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-55)

- $state **object** - &lt;p&gt;for INTERNAL use only&lt;/p&gt;

### run

[](#run-1)

```
mixed FutoIn\RI\ScopedSteps::run()

```

Execute all steps until nothing is left

- Visibility: **public**

### add

[](#add-3)

```
\FutoIn\AsyncSteps FutoIn\RI\AsyncSteps::add(callable $func, callable $onerror)

```

Add $func step executor to end of current AsyncSteps level queue

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-56)

- $func **callable** - &lt;p&gt;void execute\_callback( AsyncSteps as\[, previous\_success\_args\] )&lt;/p&gt;
- $onerror **callable** - &lt;p&gt;OPTIONAL: void error\_callback( AsyncSteps as, error )&lt;/p&gt;

### copyFrom

[](#copyfrom-3)

```
\FutoIn\AsyncSteps FutoIn\RI\AsyncSteps::copyFrom(\FutoIn\RI\AsyncSteps $other)

```

Copy steps from other AsyncSteps, useful for sub-step cloning

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-57)

- $other **[FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)** - &lt;p&gt;model AsyncSteps object for re-use&lt;/p&gt;

### parallel

[](#parallel-3)

```
\FutoIn\AsyncSteps FutoIn\RI\AsyncSteps::parallel(callable $onerror)

```

Create special object to queue steps for execution in parallel

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-58)

- $onerror **callable** - &lt;p&gt;OPTIONAL: void error\_callback( AsyncSteps as, error )&lt;/p&gt;

### state

[](#state-3)

```
\StdClass FutoIn\RI\AsyncSteps::state()

```

Access AsyncSteps state object

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

### success

[](#success-3)

```
mixed FutoIn\RI\AsyncSteps::success()

```

Set "success" state of current step execution

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

### successStep

[](#successstep-3)

```
mixed FutoIn\RI\AsyncSteps::successStep()

```

Call success() or add efficient dummy step equal to as.success() in behavior (depending on presence of other sub-steps)

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

### error

[](#error-3)

```
mixed FutoIn\RI\AsyncSteps::error(string $name, string $error_info)

```

Set "error" state of current step execution

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-59)

- $name **string** - &lt;p&gt;Type of error&lt;/p&gt;
- $error\_info **string** - &lt;p&gt;Error description to be put into "error\_info" state field&lt;/p&gt;

### setTimeout

[](#settimeout-3)

```
mixed FutoIn\RI\AsyncSteps::setTimeout(integer $timeout_ms)

```

Delay further execution until as.success() or as.error() is called

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-60)

- $timeout\_ms **integer** - &lt;p&gt;Timeout in milliseconds&lt;/p&gt;

### \_\_invoke

[](#__invoke-3)

```
mixed FutoIn\RI\AsyncSteps::__invoke()

```

PHP-specific alias for success()

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

### setCancel

[](#setcancel-3)

```
mixed FutoIn\RI\AsyncSteps::setCancel($oncancel)

```

Set cancellation callback

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-61)

- $oncancel **mixed** - &lt;p&gt;void cancel\_callback( AsyncSteps as ) \\note Please see the specification&lt;/p&gt;

### execute

[](#execute-3)

```
mixed FutoIn\RI\AsyncSteps::execute()

```

Start execution of AsyncSteps

It can be called only on root instance of AsyncSteps

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

### cancel

[](#cancel-2)

```
mixed FutoIn\RI\AsyncSteps::cancel()

```

Cancel execution of AsyncSteps

It can be called only on root instance of AsyncSteps

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

### loop

[](#loop-3)

```
mixed FutoIn\RI\AsyncSteps::loop(callable $func, string $label)

```

Execute loop until *as.break()* is called

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-62)

- $func **callable** - &lt;p&gt;loop body callable( as )&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### loopForEach

[](#loopforeach-3)

```
mixed FutoIn\RI\AsyncSteps::loopForEach(array $maplist, callable $func, string $label)

```

For each *map* or *list* element call *func( as, key, value )*

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-63)

- $maplist **array**
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### repeat

[](#repeat-3)

```
mixed FutoIn\RI\AsyncSteps::repeat(integer $count, callable $func, string $label)

```

Call *func(as, i)* for *count* times

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-64)

- $count **integer** - &lt;p&gt;how many times to call the &lt;em&gt;func&lt;/em&gt;&lt;/p&gt;
- $func **callable** - &lt;p&gt;loop body &lt;em&gt;func( as, key, value )&lt;/em&gt;&lt;/p&gt;
- $label **string** - &lt;p&gt;optional label to use for &lt;em&gt;as.break()&lt;/em&gt; and &lt;em&gt;as.continue()&lt;/em&gt; in inner loops&lt;/p&gt;

### breakLoop

[](#breakloop-3)

```
mixed FutoIn\RI\AsyncSteps::breakLoop(string $label)

```

Break execution of current loop, throws exception

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-65)

- $label **string** - &lt;p&gt;unwind loops, until &lt;em&gt;label&lt;/em&gt; named loop is exited&lt;/p&gt;

### continueLoop

[](#continueloop-3)

```
mixed FutoIn\RI\AsyncSteps::continueLoop(string $label)

```

Ccontinue loop execution from the next iteration, throws exception

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-66)

- $label **string** - &lt;p&gt;break loops, until &lt;em&gt;label&lt;/em&gt; named loop is found&lt;/p&gt;

### \_\_set

[](#__set-3)

```
mixed FutoIn\RI\AsyncSteps::__set(string $name, mixed $value)

```

state() access through AsyncSteps interface / set value

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-67)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;
- $value **mixed** - &lt;p&gt;state variable value&lt;/p&gt;

### \_\_get

[](#__get-3)

```
mixed FutoIn\RI\AsyncSteps::__get(string $name)

```

state() access through AsyncSteps interface / get value

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-68)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_isset

[](#__isset-3)

```
boolean FutoIn\RI\AsyncSteps::__isset(string $name)

```

state() access through AsyncSteps interface / check value exists

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-69)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

### \_\_unset

[](#__unset-3)

```
mixed FutoIn\RI\AsyncSteps::__unset(string $name)

```

state() access through AsyncSteps interface / delete value

- Visibility: **public**
- This method is defined by [FutoIn\\RI\\AsyncSteps](#FutoIn-RI-AsyncSteps.md)

#### Arguments

[](#arguments-70)

- $name **string** - &lt;p&gt;state variable name&lt;/p&gt;

###  Health Score

26

—

LowBetter than 43% of packages

Maintenance0

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~26 days

Recently: every ~61 days

Total

11

Last Release

3997d ago

Major Versions

0.99.8 → 1.0.02014-10-18

PHP version history (3 changes)0.99PHP &gt;=5.5

0.99.8PHP ~5.5

1.1.0PHP &gt;=5.6

### Community

Maintainers

![](https://www.gravatar.com/avatar/fe9158a3f3da987ddd751e778ab335ea186ea06672c5ef08c6768d4e789f718c?d=identicon)[futoin](/maintainers/futoin)

---

Top Contributors

[![andvgal](https://avatars.githubusercontent.com/u/6080632?v=4)](https://github.com/andvgal "andvgal (47 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/futoin-core-php-ri-asyncsteps/health.svg)

```
[![Health](https://phpackages.com/badges/futoin-core-php-ri-asyncsteps/health.svg)](https://phpackages.com/packages/futoin-core-php-ri-asyncsteps)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
