Icicle is a PHP library for writing asynchronous code using synchronous coding techniques

Related tags

Event icicle
Overview

Icicle is now deprecated in favor of Amp v2.0. This version is is currently under development, but close to release. The v2.0 branches are amp_v2 in all packages except the main Amp package, loop package, and postgres package, where v2.0 is the master branch.

Icicle

Icicle is a PHP library for writing asynchronous code using synchronous coding techniques.

Icicle uses Coroutines built with Awaitables and Generators to facilitate writing asynchronous code using techniques normally used to write synchronous code, such as returning values and throwing exceptions, instead of using nested callbacks typically found in asynchronous code.

Build Status Coverage Status Semantic Version MIT License @icicleio on Twitter

Library Components

  • Coroutines are interruptible functions for building asynchronous code using synchronous coding patterns and error handling.
  • Awaitables act as placeholders for future values of asynchronous operations. Awaitables can be yielded in coroutines to define interruption points. Callbacks registered with awaitables may return values and throw exceptions.
  • Observables represent asynchronous sets of values, providing operations usually associated with sets such as map, filter, and reduce. Observables also can be iterated over asynchronously within a coroutine.
  • Loop (event loop) is used to schedule functions, run timers, handle signals, and poll sockets for pending data or await for space to write.

Available Packages

  • Stream: Common coroutine-based interface for reading and writing data.
  • Socket: Asynchronous stream socket server and client.
  • Concurrent: Provides an easy to use interface for parallel execution with non-blocking communication and task execution.
  • DNS: Asynchronous DNS query executor, resolver and connector.
  • Filesystem: Asynchronous filesystem access.
  • HTTP: Asynchronous HTTP server and client.
  • WebSocket: Asynchronous WebSocket server and client.
  • React Adapter: Adapts the event loop and awaitables of Icicle to interfaces compatible with components built for React.

Documentation and Support

Requirements
  • PHP 5.5+ for v0.9.x branch (current stable) and v1.x branch (mirrors current stable)
  • PHP 7 for v2.0 (master) branch supporting generator delegation and return expressions
Installation

The recommended way to install Icicle is with the Composer package manager. (See the Composer installation guide for information on installing and using Composer.)

Run the following command to use Icicle in your project:

composer require icicleio/icicle

You can also manually edit composer.json to add Icicle as a project requirement.

// composer.json
{
    "require": {
        "icicleio/icicle": "^0.9"
    }
}
Suggested
  • pcntl extension: Enables custom signal handling.
  • ev extension: Extension providing the most performant event loop implementation.
  • uv extension (PHP 7 only): Another extension providing a more performant event loop implementation (experimental).

Example

The example script below demonstrates how awaitables can be yielded in a coroutine to create interruption points. Fulfillment values of awaitables are sent to the coroutine and rejection exceptions are thrown into the coroutine.

#!/usr/bin/env php
<?php

require dirname(__DIR__) . '/vendor/autoload.php';

use Icicle\Awaitable;
use Icicle\Coroutine\Coroutine;
use Icicle\Loop;

$generator = function () {
    try {
        // Sets $start to the value returned by microtime() after approx. 1 second.
        $start = (yield Awaitable\resolve(microtime(true))->delay(1));

        echo "Sleep time: ", microtime(true) - $start, "\n";

        // Throws the exception from the rejected promise into the coroutine.
        yield Awaitable\reject(new Exception('Rejected promise'));
    } catch (Exception $e) { // Catches promise rejection reason.
        echo "Caught exception: ", $e->getMessage(), "\n";
    }

    yield Awaitable\resolve('Coroutine completed');
};

$coroutine = new Coroutine($generator());

$coroutine->done(function ($data) {
    echo $data, "\n";
});

Loop\run();
Comments
  • Fail to run the example code

    Fail to run the example code

    I cd to the directory where test.php locate and run composer require icicle and then copy the example code. But all of the examples in readme are failed. Here is a piece of the example code:

    <?php
    
    require 'vendor/autoload.php';
    use Icicle\Coroutine\Coroutine;
    use Icicle\Dns\Executor\Executor;
    use Icicle\Dns\Resolver\Resolver;
    use Icicle\Loop;
    use Icicle\Socket\Client\Connector;
    
    $generator = function () {
        try {
            $resolver = new Resolver(new Executor('8.8.8.8'));
    
            // This coroutine pauses until yielded coroutine is fulfilled or rejected.
            $ips = (yield $resolver->resolve('example.com'));
    
            $connector = new Connector();
    
            // This coroutine pauses again until yielded coroutine is fulfilled or rejected.
            $client = (yield $connector->connect($ips[0], 80));
    
            echo "Asynchronously connected to example.com:80\n";
        } catch (Exception $exception) {
            echo "Asynchronous task failed: {$exception->getMessage()}\n";
        }
    };
    
    $coroutine = new Coroutine($generator());
    
    Loop\run();
    ?>
    

    And I got a Fetal error: Fatal error: Class 'Icicle\Dns\Resolver\Resolver' not found

    documentation 
    opened by rylanathk 6
  • SocketEvent raise exception for fd resource

    SocketEvent raise exception for fd resource

    The constructor of Icicle\Loop\Events\SocketEvent throws an Exception when $resource is an fd (int). This error emerged whlle testing your react/loop integration with zeromq.

    bug 
    opened by goddanao 6
  • PHP 5.4 using PHP 5.5 features

    PHP 5.4 using PHP 5.5 features

    Hey friend,

    https://github.com/icicleio/Icicle/blob/5797e370acb24e64c70494a35f4aad0f9de325c3/src/Coroutine/Coroutine.php#L132-L134

    finally is a PHP 5.5 feature, but phpunit.xml.dist and composer.json both stipulate PHP 5.4 as a minimum version. Am I missing something or should the minimum version be bumped to 5.5?

    Edit: also, generator syntax is (PHP 5 >= 5.5.0)

    opened by assertchris 6
  • Fatal error: Class 'Icicle\Http\Client not found.

    Fatal error: Class 'Icicle\Http\Client not found.

    I tried to run example code, but getting Fatal error: Class 'Icicle\Http\Client not found exception.

    composer.json

    {
        "require": {
            "icicleio/icicle": "^0.9.6",
            "icicleio/http": "^0.3"
        }
    }
    

    PHP

    >php -v
    PHP 5.6.8 (cli) (built: Apr 15 2015 15:07:09)
    Copyright (c) 1997-2015 The PHP Group
    Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
    

    Examplecode

    <?php
    require './vendor/autoload.php';
    use Icicle\Coroutine;
    use Icicle\Http;
    use Icicle\Loop;
    use Icicle\Stream;
    
    Coroutine\create(function () {
        // Infinitely get input from the console until the user terminates the program.
        while (true) {
            // Read a line of text from standard input.
            // The program will block here, waiting for another line of input.
            $line = fgets(STDIN);
    
            // Trim extra newlines and whitespace.
            $url = trim($line);
    
            // Fetch the file at the given URL with an HTTP client.
            // We use a new coroutine here so that the download will run independently
            // of our loop.
            Coroutine\create(function () use ($url) {
                $client = new Http\Client();
                $response = (yield $client->request('GET', $url));
    
                // Collect the response body and write it to a file.
                $contents = (yield Stream\readAll($response->getBody()));
                $file = basename($url);
                file_put_contents($file, $contents);
            });
        }
    });
    
    // Run the event loop, as usual.
    Loop\run();
    
    opened by kirensiva 3
  • Icicle performance test

    Icicle performance test

    I have 2 download scripts async_downloader.php and downloader.php. Both are for getting the contents from URLs. First one is using Icicle co routine to increase the performance and the second one is a usual php loop. I have logged start time and end time of both the scripts, but there is no much performance difference I saw. Some times normal php script is faster than Icicle co routine. My codes are given below. Please advice me if I am missing anything in the scripts.

    async_downloader.php

    require './vendor/autoload.php';
    use Icicle\Coroutine;
    use Icicle\Loop;
    use Icicle\Stream;
    echo 'Start Time:' . date('Y-m-d H:i:s') . PHP_EOL;
    Coroutine\create(function () {
        // Infinitely get input from the console until the user terminates the program.
        $i = 0;
        $url = [
            'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
            'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
            'http://github.com/icicleio',
            'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
            'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
            'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1',
            'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1',
            'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1',
            'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1'
        ];
    
        echo count($url) . PHP_EOL;
        while ($i <= count($url)) {
            // We use a new coroutine here so that the download will run independently
            // of our loop.
            Coroutine\create(function () use ($url, $i) {
                if (isset($url[$i]) && $url[$i] != '') {
                    echo 'Processing ' . $url[$i] . PHP_EOL;
                    $content = (yield file_get_contents($url[$i]));
                    (yield file_put_contents($i . '.html', $content));
                }
            });
            $i++;
        }
    });
    echo 'End Time:' . date('Y-m-d H:i:s') . PHP_EOL;
    // Run the event loop, as usual.
    Loop\run();
    

    downloader.php

    echo 'Start Time:' . date('Y-m-d H:i:s') . PHP_EOL;
    $i = 0;
    $url = [
        'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
        'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
        'http://github.com/icicleio',
        'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
        'http://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method',
        'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1',
        'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1',
        'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1',
        'http://meta.stackoverflow.com/questions/333420/documentation-update-august-29th?cb=1'
    ];
    while ($i <= count($url)) {
    
        if (isset($url[$i]) && $url[$i] != '') {
            echo 'Processing ' . $url[$i] . PHP_EOL;
    
            $content = (file_get_contents($url[$i]));
            (file_put_contents($i . '.html', $content));
        }
        $i++;
    }
    echo 'End Time:' . date('Y-m-d H:i:s') . PHP_EOL;
    
    opened by kirensiva 3
  • stream_select behaviour

    stream_select behaviour

    In SelectLoop.php's call to stream_select the 'read' and 'write' arrays are populated such that the array keys are the integer cast of the resource id and the values are the resource itself. Usually the output from stream_select preserves the array keys and this is passed to pollManager->handle.

    However I have found the array keys are not always preserved. In my testing with a single socket the key becomes 0 instead of the integer cast of the resource id. This breaks pollManager->handle, causing it to not find the socket. I cannot explain why it only happens sometimes.

    The following debugging code added to SelectLoop.php's dispatch function can detect the problem in my application: if ($count) { /// begin insert debugging code /// foreach ($read as $id => $resource) { if ($id != (int) $resource) { die("stream_select mismatch $id != $resource"); } } // end insert debugging code //// }

    The fix is to modify the 'handle' function in SelectIoManager.php. Replacing: foreach ($active as $id => $resource) { ... With: foreach ($active as $resource) { $id = (int) $resource; ...

    bug 
    opened by barrylb 2
  • Ambiguous event extension description

    Ambiguous event extension description

    This part of the documentation is very confusing. Which one is more performant?

    • event extension: Allows for the most performant event loop implementation.
    • libevent extension: Similar to the event extension, it allows for a more performant event loop implementation.
    opened by nicholasruunu 2
  • v0.3.0

    v0.3.0

    New Features

    • Added interface for seekable streams, \Icicle\Stream\SeekableStreamInterface, and the class \Icicle\Stream\Sink that implements the interface and acts as a seekable buffered sink.
    • Added splat() method to \Icicle\Promise\PromiseInterface. If a promise fulfills with an array or Traversable, this method uses the elements of the array as arguments to the given callback function similar to the ... (splat) operator.
    • Added verify peer options to \Icicle\Socket\Server\ServerFactory. Normally peer verification is off on the server side, but the options allow it to be turned on if desired.
    • Added cn option to \Icicle\Socket\Client\Connector that defaults to the same value as the name option. Needed for PHP 5.5 for certificate validation if the CN name does not exactly match the peer name as SAN support was not implemented until PHP 5.6. (e.g., '*.google.com' may be used for the cn option to match a wildcard certificate.)

    Changes

    • \Icicle\Stream\Stream now closes only once all data has been read from the stream if end() is called on the stream. The logic for closing the stream was moved to the send() method, allowing extending classes to end the stream from an overridden send() method instead of calling end(), which results in a recursive call to send().
    • \Icicle\Promise\PromiseInterface::tap() and \Icicle\Promise\PromiseInterface::cleanup() were changed so that if the callback given to tap() or cleanup() returns a promise, the promise returned from these methods is not fulfilled until the promise returned from the callback is resolved. If the promise returned from the callback is rejected, the promise returned from these methods is rejected for the same reason.
    • Removed always() and after() methods from \Icicle\Promise\PromiseInterface, since these methods encouraged poor practices and should be replaced with cleanup() or done().
    • Removed optional Exception parameter from \Icicle\Socket\Stream\ReadableStream::close(), \Icicle\Socket\Stream\WritableStream::close(), \Icicle\Socket\Stream\DuplexStream::close(), \Icicle\Socket\Server\Server::close(), and \Icicle\Socket\Datagram\Datagram::close().
    • Removed poll() and await() methods from stream interfaces. These methods only make sense on stream sockets and relied heavily on the state of the stream. The methods are still available in \Icicle\Socket\Stream\ReadableStreamTrait and \Icicle\Socket\Stream\WritableStreamTrait as protected methods if needed by extending classes to implement special functionality using the raw PHP stream.
    • Modified implementations of \Icicle\Stream\ReadableStreamInterface::pipe() to call end() on the writable stream once the stream becomes unreadable if $endWhenUnreadable is true. Prior, end() would only be called if the stream was closed.

    Bug Fixes

    • Fixed bug in \Icicle\Stream\PipeTrait and \Icicle\Socket\Stream\PipeTrait that would rejected the returned promise even if the stream was closed or ended normally.
    • Fixed circular reference in stream sockets and servers that delayed garbage collection after closing the server or stream.
    opened by trowski 2
  • Memory leak in Loop

    Memory leak in Loop

    I've found a memory leak inside the icicle loop when yielding from a co routine.

    This can be replicated with the below code:

    <?php
    
    require_once("./vendor/autoload.php");
    
    use Icicle\Loop;
    use Icicle\Coroutine\Coroutine;
    
    function gen()
    {
        while(true){
            yield array_fill(0, 10000, 4);
            print memory_get_usage(false).PHP_EOL;
        }
    }
    
    Loop\immediate(
        function() {
            new Coroutine(gen());
        }
    );
    
    Loop\Run();
    

    This is possibly related to https://bugs.php.net/bug.php?id=69887 and https://bugs.php.net/bug.php?id=62210 which is reported to be fixed in php7.1.

    bug 
    opened by karl-malakoff 1
  • v0.4.0

    v0.4.0

    New Features

    • Process signals are now treated like other loop events and are represented by objects implementing Icicle\Loop\Events\SignalInterface. Use the Icicle\Loop\Loop::signal() method to create signal event objects. See the documentation for more information.
    • Added method isEmpty() to Icicle\Loop\Loop that determines if there are any events pending in the loop.
    • Support for unix sockets added to Icicle\Socket\Client\Connector by passing the file path as the first parameter and null for the port and adding 'protocol' => 'unix' to the array of options.
    • Support for unix sockets also added to Icicle\Socket\Server\ServerFactory by passing the file path as the first parameter and null for the port and adding 'protocol' => 'unix' to the array of options.
    • Added ability to restart timers if they were stopped using the start() method. Note that the methods on Icicle\Loop\Events\TimerInterface have changed (see Changes section).
    • Added execute() method to Icicle\Loop\Evnets\ImmediateInterface to execute the immediate again if desired.

    Changes

    • The Event Emitter package is no longer a dependency since process signals have been refactored into event objects (see above). Icicle\Loop\LoopInterface no longer extends Icicle\EventEmitter\EventEmitterInterface.
    • Related to the above changes to signal handling, following methods have been removed from Icicle\Loop\Loop:
      • addSignalHandler()
      • removeSignalHandler()
      • removeAllSignalHandlers()
    • Icicle\Loop\Events\TimerInterface changed to support restarting timers. start() method added, cancel() renamed to stop().
    • Icicle\Loop\LoopInterface objects should no longer pass the socket resource to socket event callbacks. This only affects custom implementations of Icicle\Loop\LoopInterface, no changes need to be made to code using socket event objects.
    • Changed order of arguments to create timers in Icicle\Loop\LoopInterface to be consistent with other methods creating events. Again, this change only will affect custom loop implementations, not user code since argument order did not change in Icicle\Loop\Loop.
    opened by trowski 1
  • Add a Gitter chat badge to README.md

    Add a Gitter chat badge to README.md

    icicleio/Icicle now has a Chat Room on Gitter

    @trowski has just created a chat room. You can visit it here: https://gitter.im/icicleio/Icicle.

    This pull-request adds this badge to your README.md:

    Gitter

    If my aim is a little off, please let me know.

    Happy chatting.

    PS: Click here if you would prefer not to receive automatic pull-requests from Gitter in future.

    opened by gitter-badger 1
  • documentation in icicle.io domain is not available / parked

    documentation in icicle.io domain is not available / parked

    it seems the domain icicle.io is not hosting the documentation anymore, would be nice to move perhaps to github.io or some other place when the old one is not coming back

    opened by douglasjam 0
  • defunct not exit

    defunct not exit

    have same icicle version (0.9.6) and have same cli code, 100%. one on ubuntu server, and other on centos server. using Fork:spawn and DefaultPool on ubuntu server working fine, but on centos server i got a lot of php <defunct> and makes cannot allocate memory, any suggestions ?

    all extension is same on both server : ev extenstion, pcntl extension all same

    opened by pentatonicfunk 2
Releases(v0.9.6)
  • v0.9.6(Mar 31, 2016)

    Added

    • Added Icicle\execute() function that takes a callback (may be a normal function, return an Awaitable, or be a coroutine) and runs the function within a running event loop. This function may be used to initialize and run a program instead of manually creating an initial Coroutine instance and calling Icicle\Loop\run().

    Fixed

    • Fixed #18 resulting from stream_select() on Windows sometimes removing array keys if only a single socket is in the loop.
    • Fixed a bug in Icicle\Loop\SelectLoop that could result in the callback on an IO watcher to be erroneously invoked with $expired set to true if Io::listen() is called successively without an event occurring between invocations.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.5(Feb 21, 2016)

    Changed

    • Awaitables are now synchronously resolved. Callbacks are immediately invoked when an awaitable is resolved. Callbacks registered with then(), done() or other methods will invoke the callback immediately if the awaitable has been resolved. This change was made to improve performance in coroutines. If resolving an awaitable in an object, be sure to cleanup the objects state before resolving the awaitable. With this change, methods on the object could be called before the method resolving the awaitable finishes. While some changes were needed within this library and some of the basic Icicle packages, application code built on coroutines should see no effects from this change.
    • Renamed signalHandlingEnabled() to isSignalHandlingEnabled() in Icicle\Loop\Loop to be consistent with other method naming conventions. The function Icicle\Loop\signalHandlingEnabled() was also renamed to Icicle\Loop\isSignalHandlingEnabled().
    • Immediates are now invoked only if there are no active events in the loop. An active event is one where the event has occurred, but the callback has not yet been invoked. As before, only a single Immediate is invoked before polling streams for data, invoking timers, or checking for signals.
    • Cancelled coroutines now continue executing their generator function, allowing coroutines to execute cleanup code in try/catch blocks. As before, if a coroutine is waiting on an awaitable at the time it is cancelled, that awaitable is still cancelled. The cancellation reason is then thrown into the generator.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.4(Jan 19, 2016)

    Added

    • Added of(), fail(), concat(), zip(), and range() functions to the Icicle\Observable namespace. See each function for more information.
    • Added reduce() function to Icicle\Observable\Observable that executes an accumulator function on each emitted value, returning an observable that emits the current accumulated value after each invokation of the accumulator.

    Changed

    • Passing null (now the default argument) to Icicle\Loop\Loop::maxQueueDepth() or Icicle\Loop\maxQueueDepth() will return the current max queue depth without modifying it.
    • Icicle\Observable\Emitter can delegate to another instance of Icicle\Observable\Observable by emitting the observable. Values from the emitted observable will then be emitted as though they were emitted by the delegating observable. The $emit callable will resolve with the return value of the emitted observable.
    • Icicle\Observable\Emitter now allows multiple coroutines to be created from the $emit callable simultaneously. This makes no difference for emitters using yield with $emit, but simplifies implementations using $emit as part of a callback that may be called before the previous value has finished emitting. See Icicle\Observable\merge() for an example of a function that uses $emit as a callback.
    • If an awaitable emitted from Icicle\Observable\Emitter is rejected, the observable will fail with the exception used to reject the awaitable.
    • Icicle\Observable\observe() now takes a callable $onDisposed argument that is invoked with the callable passed to the emitting function if the observable is disposed. This function can be used to remove the callable from the event emitter.

    Fixed

    • Fixed #14 caused by queued function arguments being retained in the loop until a full tick completed, consuming more memory than necessary. Arguments are now freed immediately after executing each queued function.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.3(Jan 5, 2016)

    Added

    • Icicle\Observable\Emitter gained an optional $onDisposed parameter on the constructor accepting a callback function that is executed if the observable is disposed (either automatically or explicitly). This callback can either be a regular function, return an awaitable, or a coroutine. If the callback function returns an awaitable or is a coroutine, the observable is not disposed until the awaitable resolves. If the callback throws an exception (or the awaitable rejects), that exception will be used to dispose of the observable.

    Changed

    • Cancelling a coroutine will no longer throw the cancellation reason into the generator. Generator execution is simply terminated. Repeatedly throwing the exception into the generator caused unpredictable and unexpected behaviors. Use finally blocks or cancellation functions on awaitables if it is necessary to clean up state in coroutines. This method is far cleaner and prevents unintentional state-altering code being executed after cancellation.
    • Cancelled awaitables will now report as pending until any cancellation function has been invoked.

    Fixed

    • Fixed issue where the coroutine created from a yielded generator in a coroutine would not be cancelled if the parent coroutine was cancelled (issue only affected v0.9.x and v1.x branches).
    Source code(tar.gz)
    Source code(zip)
  • v0.9.2(Dec 18, 2015)

    Changes

    • Watchers now pass the watcher object to the callback function when an event occurs. The watcher object is passed as the last function argument (in the case of timers and immediates, the only argument).
    • All watchers now include setData() and getData() methods for setting and getting data associated with the watcher. Functions creating watchers have an optional $data parameter that can be used to set the data associated with a watcher when it is created.
    • The functions creating timers and immediates no longer accept a variadic list of arguments to pass to the callback invoked by the timer or immediate. Instead the timer or immediate watcher object is passed to the callback. Use getData() and setData() on the watcher for passing data to the callback.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.1(Dec 3, 2015)

    New Features

    • Icicle\Loop\Watcher\Timer gained an again() method that will restart the timer as though it were just started even if the timer is currently pending.
    • Icicle\Loop\poll() and Icicle\Loop\await() now have a third parameter that if true (defaults to false) will create a persistent IO watcher object that will remain active once listen() is called until cancel() is called on the watcher. Icicle\Loop\Watcher\Io gained a isPersistent() method returning a boolean.

    Changes

    • Dropped support for the event and libevent extensions. These extensions have been replaced by the ev extension and are no longer being actively developed.
    • Cancelling a coroutine will throw the cancellation reason into the generator and cancel any yielded awaitables.

    Bug Fixes

    • Fixed issue where disposing of an observable would not throw the disposal reason from ObservableIterator::getReturn().
    Source code(tar.gz)
    Source code(zip)
  • v0.9.0(Dec 2, 2015)

    Changes

    • All interface names have been changed to remove the Interface suffix. Most interfaces simply had the suffix removed, but there are a few exceptions - more below.
    • Promises are now Awaitables
      • The Icicle\Promise namespace has been renamed to Icicle\Awaitable. Icicle\Promise\PromiseInterface is now Icicle\Awaitable\Awaitable.
      • Icicle\Awaitable\Promise (previously Icicle\Promise\Promise) now extends a new class Icicle\Awaitable\Future that implements Icicle\Awaitable\Awaitable. Future uses protected methods to resolve the awaitable, so it can be extended to create awaitables that are resolved in different ways. The functionality of Promise has not changed.
      • Icicle\Coroutine\Coroutine now also extends Icicle\Awaitable\Future. The functionality of Coroutine has not changed, but it should be faster to create a Coroutine object. Icicle\Coroutine\CoroutineInterface has been removed.
    • The Icicle\Loop\Events namespace was renamed to Icicle\Loop\Watcher. Interfaces in the namespace were removed except EventInterface which was renamed to Watcher.
    • Icicle\Loop\Events\SocketEvent was renamed to Icicle\Loop\Watcher\Io since more than just 'sockets' can be used.
    • Icicle\Coroutine\create() no longer throws if the callback throws or returns a promise, instead it returns a rejected coroutine.
    • Icicle\Awaitable\Awaitable::timeout() (previously Icicle\Promise\PromiseInterface::timeout()) now takes a callback function that is invoked if the parent awaitable is not resolved in the given timeout. The promise returned from this method is resolved by the callback function. This callback function can still cancel the parent promise if desired or perform any other action.
    • Rejecting an awaitable now requires an exception instance.
    • Icicle\Awaitable\Awaitable::cancel() (previously Icicle\Promise\PromiseInterface::cancel() now requires an exception instance or null. If null, an instance of Icicle\Awaitable\Exception\CancelledException is used.
    • Icicle\Awaitable\Awaitable::timeout() (previously Icicle\Promise\PromiseInterface::timeout() now takes a callable or null as the second argument. The awaitable returned from timeout() is resolved by the callable or rejected with an instance of Icicle\Awaitable\Exception\TimeoutException if no callable is given.

    New Features

    • Added observables that represent asynchronous collections. Observables implement Icicle\Observable\Observable and include array-like methods including Observable::map() and Observable::filter(). Observables can be iterated over asynchronously in a coroutine using the iterator returned from Observable::getIterator(). See the example in examples/observable.php and the documentation (work-in-progress) for more information.
    • Icicle\Awaitable\Delayed was added as a publicly resolvable awaitable. This type of awaitable should not be returned from public APIs, but rather only used internally within a class or Coroutine to create an awaitable that can be resolved later. So in other words, a class method or function should never return a Delayed. In general, methods and functions should not be returning awaitables as part of their public API. The public API should consist of Generators that can be used as Coroutines.
    • Icicle\Awaitable\Awaitable now has a method uncancellable() that returns an awaitable that cannot be cancelled (the cancel() method is a no-op).
    Source code(tar.gz)
    Source code(zip)
  • v0.8.3(Sep 18, 2015)

    New Features

    • Added Coroutine\run() function that may be used to create an initial coroutine that runs the rest of the application. This function should not be called in a running event loop.
    • All loop events can now be referenced/unreferenced like timers using the reference() and unreference() methods on event objects. Only referenced events will prevent an event loop from exiting the run() method. Signal events are created as unreferenced, while all other events are created as referenced.
    Source code(tar.gz)
    Source code(zip)
  • v0.8.2(Sep 10, 2015)

    Bug Fixes

    • Fixed issue where a promise would report as pending for some time after being cancelled.
    • Timers that are restarted after being unreferenced would become referenced again. This issue has now been fixed.
    Source code(tar.gz)
    Source code(zip)
  • v0.8.1(Aug 28, 2015)

    New Features

    • Added Icicle\Loop\EvLoop supporting the ev extension. This loop is now the default event loop used if the ev extension is available.
    • Icicle\Promise\map() now accepts any number of arrays like array_map(), passing an element of each array as an argument to the callback function.

    Bug Fixes

    • Coroutines are paused immediately upon cancellation to ensure execution does not continue after cancellation.
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Aug 15, 2015)

    New Features

    • The default event loop can be swapped during execution. Normally this is not recommended and will break a program, but it can be useful in certain circumstances (forking, threading).
    • Added the function Icicle\Loop\with() that accepts a function that is run in a separate loop from the default event loop (a specific loop instance can be provided to the function). The default loop is blocked while running the loop.
    • Icicle\Loop\Events\SocketEventInterface and Icicle\Loop\Events\SignalInterface gained a setCallback() method that allows the callback invoked when an event occurs to be swapped without needing to create a new event.

    Changes

    • The cancellation callable is no longer passed to the Icicle\Promise\Promise constructor, it should be returned from the resolver function passed to the constructor. This change was made to avoid the need to create reference variables to share values between functions. Instead values can just be used in the cancellation function returned from the resolver. The resolver function must return a callable or null.
    • Cancelling a promise is now an asynchronous task. Calling Icicle\Promise\Promise::cancel() does not immediately call the cancellation method (if given), it is called later (like a function registered with then()).
    • Icicle/Promise/PromiseInterface now includes an isCancelled() method. When a promise is cancelled, this method will return true once the promise has been cancelled. Note that if a child promise is rejected due to an $onRejected callable throwing after cancelling the parent promise, isCancelled() of the child promise will return false because the promise was not cancelled, it was rejected from the $onRejected callback.

    Bug Fixes

    • Fixed issue where Icicle\Loop\SelectLoop would not dispatch a signal while blocking. The issue was fixed by adding a periodic timer that checks for signals that may have arrived. The interval of this timer can be set with Icicle\Loop\SelectLoop::signalInterval().
    Source code(tar.gz)
    Source code(zip)
  • v0.7.1(Jul 18, 2015)

    • Modified Icicle\Promise\Promise for better performance. The modified implementation eliminates the creation of one closure and only creates a queue of callbacks if more than one callback is registered to be invoked on fulfillment or rejection. No changes were made to functionality.
    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Jul 2, 2015)

  • v0.6.0(Jul 1, 2015)

    Changes

    • The methods Icicle\Stream\ReadableStreamInterface::pipe(), Icicle\Socket\Client\ClientInterface::enableCrypto(), and Icicle\Socket\Client\ConnectorInterface::connect() now return a Generator instead of an Icicle\Promise\PromiseInterface object. The returned generator can be yielded directly in a coroutine. A promise can be created from these methods if desired by passing the returned Generator to the Icicle\Coroutine\Coroutine constructor (e.g., $coroutine = new Coroutine($connector->connect($host, $port)). This change was made for better performance with yield from in PHP 7.
    • Icicle\Loop\Events\SocketEventInterface::listen() now uses 0 to indicate no timeout.
    • All stream methods have a $timeout parameter, not only stream sockets. All $timeout parameters now use 0 to indicate no timeout.
    • Icicle\Stream\ReadableStreamInterface::read() and Icicle\Stream\ReadableStreamInterface::pipe() now use 0 to specify any number of bytes instead of null.
    • Icicle\Loop\schedule() was renamed to Icicle\Loop\queue() and Icicle\Loop\maxScheduleDepth() was renamed to Icicle\Loop\maxQueueDepth(). Icicle\Loop\maxQueueDepth() requires a $depth parameter (use 0 for unlimited). The previous depth is still returned.
    • Icicle\Coroutine\async() was renamed to Icicle\Coroutine\wrap().
    • Icicle\Promise\join() was renamed to Icicle\Promise\all().
    • Exceptions were remodeled based on the exception hierarchy coming in PHP 7. Each component has a class Exception and Error that extends \Exception. The empty ExceptionInterface classes were eliminated. Several classes were renamed to use the Error suffix to indicate they represent coding errors and generally should not be caught except for cleanup/logging.
    • The protocol unix no longer needs to be explicitly specified when creating or connecting to a unix socket. Using null for the port is sufficient.
    Source code(tar.gz)
    Source code(zip)
  • v0.5.3(Jun 20, 2015)

    New Features

    • Added Promise\wait() function that can be used to synchronously wait for a promise to be resolved. The fulfillment value is returned or the rejection reason is thrown from the function. This function can be used to integrate Icicle into a synchronous environment, but generally should not be used in an active event loop.

    Changes

    • Various performance improvements when executing scheduled callbacks, executing promise callbacks, and checking for coroutine completion or cancellation.

    Bug Fixes

    • Added check in Datagram::send() on stream_socket_sendto() sending 0 bytes if the data was not immediately sent to prevent an infinite loop if the datagram is unexpectedly closed while waiting to send data.
    • Changed timer execution in SelectLoop to avoid timer drift.
    Source code(tar.gz)
    Source code(zip)
  • v0.5.2(Jun 13, 2015)

    Changes

    • ReadableStreamInterface::pipe() implementations now use coroutines instead of Promise\iterate(), significantly improving performance. The Coroutine instance is returned from pipe(), so piping may be paused if desired.
    Source code(tar.gz)
    Source code(zip)
  • v0.5.1(Jun 2, 2015)

    Bug Fixes

    • Fixed bug related to generators that never yield. If a generator was written in such a way that it may never yield, the coroutine was rejected even though the generator had not been run and could have yielded values under different circumstances. Now if a generator is immediately invalid, the coroutine is fulfilled with null instead of being rejected.
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(May 31, 2015)

    New Features

    • Icicle\Socket\Datagram classes and interfaces added to documentation and can now be used.

    Changes

    • The Loop facade class has been replaced by a set of functions defined in the Icicle\Loop namespace. Generally, calls to the Loop facade such as Loop::run() can be replaced with Loop\run() (using Icicle\Loop instead of Icicle\Loop\Loop). See the Loop documentation for more information.
    • Static functions in Icicle\Promise\Promise have been replaced with functions defined in the Icicle\Promise namespace. Calls such as Promise::resolve() can be replace with Promise\resolve() (using Icicle\Promise instead of Icicle\Promise\Promise). See the Promises documentation for more information.
    • Static functions in Icicle\Coroutine\Coroutine have been replaced with functions defined in the Icicle\Coroutine namespace. Like promises above, calls such as Coroutine::async() can be replaced with Coroutine\async() (using Icicle\Coroutine instead of Icicle\Coroutine\Coroutine). See the Coroutine documentation for more information.
    • Lazy promises should now be created with the function Icicle\Promise\lazy() instead of directly constructing a LazyPromise instance. Icicle\Promise\LazyPromise has been moved to Icicle\Promise\Structures\LazyPromise and should not be created directly, but rather is an implementation detail of Icicle\Promise\lazy().
    • The promise returned from Icicle\Socket\Server\Server::accept() will no longer be rejected with an AcceptException if accepting the client fails. The timeout option was also removed from this method, as retrying after a failed accept would make the timeout unreliable.
    • Removed tests from distributions after updating other components to no longer depend on test classes from this package. Use the --prefer-source option when installing with Composer if you wish to have tests included.

    Bug Fixes

    • Updated stream closing methods to avoid constructing an exception object if there are no pending promises to be rejected.
    Source code(tar.gz)
    Source code(zip)
  • v0.4.1(May 21, 2015)

    Changes

    • ~~Added tests back into distributions so users could verify their setup and so other components could use base test classes.~~ Removed again in v0.5.0.
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(May 21, 2015)

    New Features

    • Process signals are now treated like other loop events and are represented by objects implementing Icicle\Loop\Events\SignalInterface. Use the Icicle\Loop\Loop::signal() method to create signal event objects. See the documentation for more information.
    • Added method isEmpty() to Icicle\Loop\Loop that determines if there are any events pending in the loop.
    • Support for unix sockets added to Icicle\Socket\Client\Connector by passing the file path as the first parameter and null for the port and adding 'protocol' => 'unix' to the array of options.
    • Support for unix sockets also added to Icicle\Socket\Server\ServerFactory by passing the file path as the first parameter and null for the port and adding 'protocol' => 'unix' to the array of options.
    • Added ability to restart timers if they were stopped using the start() method. Note that the methods on Icicle\Loop\Events\TimerInterface have changed (see Changes section).
    • Added execute() method to Icicle\Loop\Evnets\ImmediateInterface to execute the immediate again if desired.

    Changes

    • The Event Emitter package is no longer a dependency since process signals have been refactored into event objects (see above). Icicle\Loop\LoopInterface no longer extends Icicle\EventEmitter\EventEmitterInterface.
    • Related to the above changes to signal handling, following methods have been removed from Icicle\Loop\Loop:
      • addSignalHandler()
      • removeSignalHandler()
      • removeAllSignalHandlers()
    • Icicle\Loop\Events\TimerInterface changed to support restarting timers. start() method added, cancel() renamed to stop().
    • Icicle\Loop\LoopInterface objects should no longer pass the socket resource to socket event callbacks. This only affects custom implementations of Icicle\Loop\LoopInterface, no changes need to be made to code using socket event objects.
    • Changed order of arguments to create timers in Icicle\Loop\LoopInterface to be consistent with other methods creating events. Again, this change only will affect custom loop implementations, not user code since argument order did not change in Icicle\Loop\Loop.
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(May 4, 2015)

    New Features

    • Added interface for seekable streams, \Icicle\Stream\SeekableStreamInterface, and the class \Icicle\Stream\Sink that implements the interface and acts as a seekable buffered sink.
    • Added splat() method to \Icicle\Promise\PromiseInterface. If a promise fulfills with an array or Traversable, this method uses the elements of the array as arguments to the given callback function similar to the ... (splat) operator.
    • Added verify peer options to \Icicle\Socket\Server\ServerFactory. Normally peer verification is off on the server side, but the options allow it to be turned on if desired.
    • Added cn option to \Icicle\Socket\Client\Connector that defaults to the same value as the name option. Needed for PHP 5.5 for certificate validation if the CN name does not exactly match the peer name as SAN support was not implemented until PHP 5.6. (e.g., '*.google.com' may be used for the cn option to match a wildcard certificate.)

    Changes

    • \Icicle\Stream\Stream now closes only once all data has been read from the stream if end() is called on the stream. The logic for closing the stream was moved to the send() method, allowing extending classes to end the stream from an overridden send() method instead of calling end(), which results in a recursive call to send().
    • \Icicle\Promise\PromiseInterface::tap() and \Icicle\Promise\PromiseInterface::cleanup() were changed so that if the callback given to tap() or cleanup() returns a promise, the promise returned from these methods is not fulfilled until the promise returned from the callback is resolved. If the promise returned from the callback is rejected, the promise returned from these methods is rejected for the same reason.
    • Removed always() and after() methods from \Icicle\Promise\PromiseInterface, since these methods encouraged poor practices and should be replaced with cleanup() or done().
    • Removed optional Exception parameter from \Icicle\Socket\Stream\ReadableStream::close(), \Icicle\Socket\Stream\WritableStream::close(), \Icicle\Socket\Stream\DuplexStream::close(), \Icicle\Socket\Server\Server::close(), and \Icicle\Socket\Datagram\Datagram::close().
    • Removed poll() and await() methods from stream interfaces. These methods only make sense on stream sockets and relied heavily on the state of the stream. The methods are still available in \Icicle\Socket\Stream\ReadableStreamTrait and \Icicle\Socket\Stream\WritableStreamTrait as protected methods if needed by extending classes to implement special functionality using the raw PHP stream.
    • Modified implementations of \Icicle\Stream\ReadableStreamInterface::pipe() to call end() on the writable stream once the stream becomes unreadable if $endWhenUnreadable is true. Prior, end() would only be called if the stream was closed.

    Bug Fixes

    • Fixed bug in \Icicle\Stream\PipeTrait and \Icicle\Socket\Stream\PipeTrait that would rejected the returned promise even if the stream was closed or ended normally.
    • Fixed circular reference in stream sockets and servers that delayed garbage collection after closing the server or stream.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.2(Apr 16, 2015)

    • Stream socket classes now implement Icicle\Socket\Stream\ReadableSocketInterface, Icicle\Socket\Stream\WritableSocketInterface, and Icicle\Socket\Stream\DuplexSocketInterface. These interfaces extend the similarly named stream interfaces and Icicle\Socket\SocketInterface, explicitly defining the $timeout parameter that is available on stream socket classes. This change does not affect compatibility, since the streams still implement the same interfaces as before, but allow for easier type-checking or type-hinting.
    • Separated pipe() implementations in streams and stream sockets into traits: Icicle\Stream\PipeTrait and Icicle\Socket\Stream\PipeTrait.
    • Added high water mark (HWM) feature to Icicle\Stream\Stream. If a HWM is provided to the constructor, writes to the stream will return pending promises if the number of bytes in the stream buffer is greater than the HWM.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Apr 16, 2015)

  • v0.2.0(Apr 16, 2015)

    • Increased minimum PHP version to 5.5 so external components can be fully compatible with Icicle and make use of Coroutines. This will avoid compatibility confusion and allow for faster development of additional components.
    • Refactored loop implementations to make use of Managers. These interfaces and classes are implementation details of each loop, as these objects are never revealed to the user. However, this change allowed Icicle\Loop\LoopInterface to be much simpler (as event objects now interact with the manager object instead of the loop object) and exposes only methods that should be publicly available.
    • Icicle\Loop\Events\PollInterface and Icicle\Loop\Events\AwaitInterface have been eliminated in favor of a single interface, Icicle\Loop\Events\SocketEventInterface. Icicle\Loop\Loop::poll() and Icicle\Loop\Loop::await() (and the corresponding methods in objects implementing Icicle\Loop\LoopInterface) both return an object implementing this interface. The mode (read or write) the returned object uses when listening on the given socket depends on which method created the Icicle\Loop\Events\SocketEventInterface object.
    • Reorganized the Socket component into more specific namespaces under Icicle\Socket: Client, Datagram, Server, and Stream.
    • Removed static constructors from Server, Datagram, and Client classes, replacing them with interfaced factories.
      • Icicle\Socket\Server\ServerFactory: Creates a server (TCP server) on a given host and port.
      • Icicle\Socket\Datagram\DatagramFactory: Creates a datagram (UDP server) on a given host and port.
      • Icicle\Socket\Client\Connector: Connects to a given host and port, with various options to control how the connection is created.
    • Icicle\Stream\ReadableStreamInterface::readTo() was eliminated, and the behavior added to Icicle\Stream\ReadableStreamInterface::read(). A second parameter, $byte was added to Icicle\Stream\ReadableStreamInterface::read() that provides the same behavior. This parameter defaults to null, allowing any bytes to be read.
    • Similar to above, Icicle\Stream\ReadableStreamInterface::pipeTo() was eliminated and a $byte parameter added to Icicle\Stream\ReadableStreamInterface::pipe().
    • Stream socket classes implementing Icicle\Stream\ReadableStreamInterface::read() (Icicle\Socket\Stream\ReadableStream and Icicle\Socket\Stream\DuplexStream) now fulfill with an empty string when the socket closes instead of rejecting with an Icicle\Socket\Exception\EofException. Subsequent reads will still reject with an Icicle\Stream\Exception\UnreadableException. This makes reading from stream in a Coroutine easier (no need for a try/catch block to only catch normal closing of the connection if looping while checking Icicle\Stream\ReadableStreamInterface::isReadable()).
    • Promise::iterate() and Promise::retry() were modified to better handle cancellation. Cancelling the promise returned by these methods will now also cancel any promises generated internally.
    Source code(tar.gz)
    Source code(zip)
Owner
icicle.io
Write asynchronous code using synchronous coding techniques with PHP using coroutines built from awaitables and generators.
icicle.io
Asynchronous coroutines for PHP 7.

Recoil An asynchronous coroutine kernel for PHP 7. composer require recoil/recoil The Recoil project comprises the following packages: recoil/api - T

Recoil 787 Dec 8, 2022
Asynchronous WebSocket server

Ratchet A PHP library for asynchronously serving WebSockets. Build up your application through simple interfaces and re-use your application without c

Ratchet 5.9k Jan 6, 2023
[READ-ONLY] The event dispatcher library for CakePHP. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp

CakePHP Event Library This library emulates several aspects of how events are triggered and managed in popular JavaScript libraries such as jQuery: An

CakePHP 21 Oct 6, 2022
PHP Application using DDD CQRS Event Sourcing with Hexagonal Architecture

PHP Application using DDD CQRS Event Sourcing with Hexagonal Architecture Application built with Ecotone Framework and powered by integrations with Pr

EcotoneFramework 65 Dec 27, 2022
Événement is a very simple event dispatching library for PHP.

Événement Événement is a very simple event dispatching library for PHP. It has the same design goals as Silex and Pimple, to empower the user while st

Igor 1.2k Jan 4, 2023
A pragmatic event sourcing library for PHP with a focus on developer experience.

EventSaucePHP EventSauce is a somewhat opinionated, no-nonsense, and easy way to introduce event sourcing into PHP projects. It's designed so storage

EventSauce 685 Dec 31, 2022
🚀 Coroutine-based concurrency library for PHP

English | 中文 Swoole is an event-driven asynchronous & coroutine-based concurrency networking communication engine with high performance written in C++

Swoole Project 17.7k Jan 5, 2023
The Hoa\Websocket library.

Hoa is a modular, extensible and structured set of PHP libraries. Moreover, Hoa aims at being a bridge between industrial and research worlds. Hoa\Web

Hoa 419 Dec 30, 2022
The Hoa\Eventsource library.

Hoa is a modular, extensible and structured set of PHP libraries. Moreover, Hoa aims at being a bridge between industrial and research worlds. Hoa\Eve

Hoa 106 Dec 5, 2022
Event-driven, non-blocking I/O with PHP.

Event-driven, non-blocking I/O with PHP. ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop, on top of

ReactPHP 8.5k Jan 8, 2023
A non-blocking concurrency framework for PHP applications. 🐘

Amp is a non-blocking concurrency framework for PHP. It provides an event loop, promises and streams as a base for asynchronous programming. Promises

Amp 3.8k Jan 6, 2023
PHP 7.4 EventStore Implementation

Prooph Event Store Common classes and interface for Prooph Event Store implementations. Installation You can install prooph/event-store via composer b

null 532 Dec 9, 2022
Reactive extensions for PHP.

This package is abandoned. Use https://github.com/ReactiveX/RxPHP instead Rx.PHP Reactive extensions for PHP. The reactive extensions for PHP are a se

Alexander 208 Apr 6, 2021
Golang's defer statement for PHP

PHP Defer A defer statement originally comes from Golang. This library allows you to use defer functionality in PHP code. Usage <?php defer($context,

null 249 Dec 31, 2022
Reactive extensions for PHP

RxPHP Reactive extensions for PHP. The reactive extensions for PHP are a set of libraries to compose asynchronous and event-based programs using obser

ReactiveX 1.6k Dec 12, 2022
Revolt is a rock-solid event loop for concurrent PHP applications.

Revolt is a rock-solid event loop for concurrent PHP applications.

Revolt PHP 586 Jan 2, 2023
WPForms coding standards are based on the WordPress Coding Standards and the PHPCompatibility Coding Standards and help create strict and high-quality code.

WPForms coding standards are based on the WordPress Coding Standards and the PHPCompatibility Coding Standards and help create strict and high-quality code.

Awesome Motive, Inc. 7 Nov 29, 2022
Promises/A+ library for PHP with synchronous support

Guzzle Promises Promises/A+ implementation that handles promise chaining and resolution iteratively, allowing for "infinite" promise chaining while ke

Guzzle 7.3k Jan 3, 2023
Docker environment for practicing pentesting techniques about SQL injection

SQL Injection Playground Docker environment for practicing pentesting techniques about SQL injection.

ommadawn46 23 Aug 2, 2022