- 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()
andunreference()
methods on event objects. Only referenced events will prevent an event loop from exiting therun()
method. Signal events are created as unreferenced, while all other events are created as referenced.
- Added
- 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.
-
New Features
- Added
Icicle\Loop\EvLoop
supporting theev
extension. This loop is now the default event loop used if theev
extension is available. Icicle\Promise\map()
now accepts any number of arrays likearray_map()
, passing an element of each array as an argument to the callback function.
- Added
-
Bug Fixes
- Coroutines are paused immediately upon cancellation to ensure execution does not continue after cancellation.
-
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
andIcicle\Loop\Events\SignalInterface
gained asetCallback()
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 acallable
ornull
. - 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 withthen()
). Icicle/Promise/PromiseInterface
now includes anisCancelled()
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.
- The cancellation callable is no longer passed to the
-
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 withIcicle\Loop\SelectLoop::signalInterval()
.
- Fixed issue where
- 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.
- Changes
- Moved Stream and Socket components to separate repositories: icicleio/stream and icicleio/socket. No API changes were made in these components from v0.6.0. If your project depends on these components, just add them as a requirement with composer.
- Changes
- The methods
Icicle\Stream\ReadableStreamInterface::pipe()
,Icicle\Socket\Client\ClientInterface::enableCrypto()
, andIcicle\Socket\Client\ConnectorInterface::connect()
now return aGenerator
instead of anIcicle\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 returnedGenerator
to theIcicle\Coroutine\Coroutine
constructor (e.g.,$coroutine = new Coroutine($connector->connect($host, $port))
. This change was made for better performance withyield from
in PHP 7. Icicle\Loop\Events\SocketEventInterface::listen()
now uses0
to indicate no timeout.- All stream methods have a
$timeout
parameter, not only stream sockets. All$timeout
parameters now use0
to indicate no timeout. Icicle\Stream\ReadableStreamInterface::read()
andIcicle\Stream\ReadableStreamInterface::pipe()
now use0
to specify any number of bytes instead ofnull
.Icicle\Loop\schedule()
was renamed toIcicle\Loop\queue()
andIcicle\Loop\maxScheduleDepth()
was renamed toIcicle\Loop\maxQueueDepth()
.Icicle\Loop\maxQueueDepth()
requires a$depth
parameter (use0
for unlimited). The previous depth is still returned.Icicle\Coroutine\async()
was renamed toIcicle\Coroutine\wrap()
.Icicle\Promise\join()
was renamed toIcicle\Promise\all()
.- Exceptions were remodeled based on the exception hierarchy coming in PHP 7. Each component has a class
Exception
andError
that extends\Exception
. The emptyExceptionInterface
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. Usingnull
for the port is sufficient.
- The methods
- New Features
- Added
Icicle\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.
- Added
- Changes
- Various performance improvements when executing scheduled callbacks, executing promise callbacks, and checking for coroutine completion or cancellation.
- Bug Fixes
- Added check in
Icicle\Socket\Datagram\Datagram::send()
onstream_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
Icicle\Loop\SelectLoop
to avoid timer drift.
- Added check in
- Changes
Icicle\Stream\ReadableStreamInterface::pipe()
implementations now use coroutines instead ofIcicle\Promise\iterate()
, significantly improving performance. TheIcicle\Coroutine\Coroutine
instance is returned frompipe()
, so piping may be paused if desired.
- 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.
- 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
-
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 asLoop::run()
can be replaced withLoop\run()
(usingIcicle\Loop
instead ofIcicle\Loop\Loop
). See the Loop documentation for more information. - Static functions in
Icicle\Promise\Promise
have been replaced with functions defined in theIcicle\Promise
namespace. Calls such asPromise::resolve()
can be replaced withPromise\resolve()
(usingIcicle\Promise
instead ofIcicle\Promise\Promise
). See the Promises documentation for more information. - Static functions in
Icicle\Coroutine\Coroutine
have been replaced with functions defined in theIcicle\Coroutine
namespace. Like promises above, calls such asCoroutine::async()
can be replaced withCoroutine\async()
(usingIcicle\Coroutine
instead ofIcicle\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 aLazyPromise
instance.Icicle\Promise\LazyPromise
has been moved toIcicle\Promise\Structures\LazyPromise
and should not be created directly, but rather is an implementation detail ofIcicle\Promise\lazy()
. - The promise returned from
Icicle\Socket\Server\Server::accept()
will no longer be rejected with anAcceptException
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.
- The Loop facade class has been replaced by a set of functions defined in the
-
Bug Fixes
- Updated stream closing methods to avoid constructing an exception object if there are no pending promises to be rejected.
- Changes
Added tests back into distributions so users could verify their setup and so other components could use base test classes.(Removed in v0.5.0)
-
New Features
- Process signals are now treated like other loop events and are represented by objects implementing
Icicle\Loop\Events\SignalInterface
. Use theIcicle\Loop\Loop::signal()
method to create signal event objects. See the documentation for more information. - Added method
isEmpty()
toIcicle\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 andnull
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 andnull
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 onIcicle\Loop\Events\TimerInterface
have changed (see Changes section). - Added
execute()
method toIcicle\Loop\Events\ImmediateInterface
to execute the immediate again if desired.
- Process signals are now treated like other loop events and are represented by objects implementing
-
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 extendsIcicle\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 tostop()
.Icicle\Loop\LoopInterface
objects should no longer pass the socket resource to socket event callbacks. This only affects custom implementations ofIcicle\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 inIcicle\Loop\Loop
.
- The Event Emitter package is no longer a dependency since process signals have been refactored into event objects (see above).
-
New Features
- Added interface for seekable streams,
Icicle\Stream\SeekableStreamInterface
, and the classIcicle\Stream\Sink
that implements the interface and acts as a seekable buffered sink. - Added
splat()
method toIcicle\Promise\PromiseInterface
. If a promise fulfills with an array orTraversable
object, 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 toIcicle\Socket\Client\Connector
that defaults to the same value as thename
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 thecn
option to match a wildcard certificate.)
- Added interface for seekable streams,
-
Changes
Icicle\Stream\Stream
now closes only once all data has been read from the stream ifend()
is called on the stream. The logic for closing the stream was moved to thesend()
method, allowing extending classes to end the stream from an overriddensend()
method instead of callingend()
, which results in a recursive call tosend()
.Icicle\Promise\PromiseInterface::tap()
andIcicle\Promise\PromiseInterface::cleanup()
were changed so that if the callback given totap()
orcleanup()
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()
andafter()
methods fromIcicle\Promise\PromiseInterface
, since these methods encouraged poor practices and should be replaced withcleanup()
ordone()
. - Removed optional
Exception
parameter fromIcicle\Socket\Stream\ReadableStream::close()
,Icicle\Socket\Stream\WritableStream::close()
,Icicle\Socket\Stream\DuplexStream::close()
,Icicle\Socket\Server\Server::close()
, andIcicle\Socket\Datagram\Datagram::close()
. - Removed
poll()
andawait()
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 inIcicle\Socket\Stream\ReadableStreamTrait
andIcicle\Socket\Stream\WritableStreamTrait
asprotected
methods if needed by extending classes to implement special functionality using the raw PHP stream. - Modified implementations of
Icicle\Stream\ReadableStreamInterface::pipe()
to callend()
on the writable stream once the stream becomes unreadable if$endWhenUnreadable
istrue
. Prior,end()
would only be called if the stream was closed.
-
Bug Fixes
- Fixed bug in
Icicle\Stream\PipeTrait
andIcicle\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.
- Fixed bug in
- Stream socket classes now implement
Icicle\Socket\Stream\ReadableSocketInterface
,Icicle\Socket\Stream\WritableSocketInterface
, andIcicle\Socket\Stream\DuplexSocketInterface
. These interfaces extend the similarly named stream interfaces andIcicle\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
andIcicle\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.
- Added
Promise::adapt()
method to create promises from any object with athen(callable $onFulfilled, callable $onRejected)
method.
- 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
andIcicle\Loop\Events\AwaitInterface
have been eliminated in favor of a single object,Icicle\Loop\Events\SocketEventInterface
.Icicle\Loop\Loop::poll()
andIcicle\Loop\Loop::await()
(and the corresponding methods in objects implementingIcicle\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 theIcicle\Loop\Events\SocketEventInterface
object.- Reorganized the Socket component into more specific namespaces under
Icicle\Socket
:Client
,Datagram
,Server
, andStream
. - 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 toIcicle\Stream\ReadableStreamInterface::read()
. A second parameter,$byte
was added toIcicle\Stream\ReadableStreamInterface::read()
that provides the same behavior. This parameter defaults tonull
, allowing any bytes to be read.- Similar to above,
Icicle\Stream\ReadableStreamInterface::pipeTo()
was eliminated and a$byte
parameter added toIcicle\Stream\ReadableStreamInterface::pipe()
. - Stream socket classes implementing
Icicle\Stream\ReadableStreamInterface::read()
(Icicle\Socket\Stream\ReadableStream
andIcicle\Socket\Stream\DuplexStream
) now fulfill with an empty string when the socket closes instead of rejecting with anIcicle\Socket\Exception\EofException
. Subsequent reads will still reject with anIcicle\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). Promise::iterate()
andPromise::retry()
were modified to better handle cancellation. Cancelling the promise returned by these methods will now also cancel any promises generated internally.
- Added
Promise::retry()
method for retrying a promise-returning operation if the promise is rejected.
- Updated the behavior the Socket component to be similar the stream socket implementation in PHP 7.
Icicle\Socket\ReadableStreamTrait::poll()
will fulfill with an empty string even if the connection has closed (stream socket is at EOF) instead of closing the stream and rejecting the promise. This change was made to match the stream socket behavior in PHP 7 that will not return true onfeof()
until a read has been attempted past EOF.
- Moved Process into separate branch for further development. Will likely be released as a separate package in the future.
- Initial release.