From 0e4194bfe82bf96f5fa61fb737e285c2cd216c35 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Fri, 13 May 2016 13:46:00 +0200 Subject: [PATCH 1/7] Add LoopDriverFactory The LoopDriverFactory SHOULD be used by driver implementations to set a default event loop driver. This can be achieved by having a Composer autoloader like that: { "autoload": { "files": ["src/bootstrap.php"] } } Where src/bootstrap.php contains the following code: use Interop\Async\EventLoop\LoopDriverFactory; class MyDriverFactory implements LoopDriverFactory { public function create() { return new MyDriver(); } } Loop::setFactory(new MyDriverFactory()); This ensures the user doesn't have to care about setting the actual driver. A user just has to require the specific event loop driver package he / she wants to use. --- src/Loop.php | 32 ++++++++++++++++++++++++++++++-- src/LoopDriverFactory.php | 13 +++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/LoopDriverFactory.php diff --git a/src/Loop.php b/src/Loop.php index c1325fd..c9d1307 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -6,11 +6,24 @@ final class Loop { use Registry; + /** + * @var LoopDriverFactory + */ + private static $factory = null; + /** * @var LoopDriver */ private static $driver = null; + /** + * Set the factory to be used to create a driver if none is passed to + * self::execute. + */ + public static function setFactory(LoopDriverFactory $factory = null) { + self::$factory = $factory; + } + /** * Execute a callback within the scope of an event loop driver. * @@ -19,11 +32,12 @@ final class Loop * * @return void */ - public static function execute(callable $callback, LoopDriver $driver) + public static function execute(callable $callback, LoopDriver $driver = null) { - $previousDriver = self::$driver; + $driver = $driver ?: $this->createDriver(); $previousRegistry = self::$registry; + $previousDriver = self::$driver; self::$driver = $driver; self::$registry = []; @@ -37,6 +51,20 @@ public static function execute(callable $callback, LoopDriver $driver) } } + /** + * Create a new driver if a factory is present, otherwise throw. + * + * @throws \LogicException if no factory is set + */ + private static function createDriver() + { + if (self::$factory === null) { + throw new \LogicException("Can't create an event loop driver without a factory."); + } + + return self::$factory->create(); + } + /** * Retrieve the event loop driver that is in scope. * diff --git a/src/LoopDriverFactory.php b/src/LoopDriverFactory.php new file mode 100644 index 0000000..a9bb129 --- /dev/null +++ b/src/LoopDriverFactory.php @@ -0,0 +1,13 @@ + Date: Fri, 13 May 2016 17:52:43 +0200 Subject: [PATCH 2/7] Fix createDriver call to be static --- src/Loop.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Loop.php b/src/Loop.php index c9d1307..eceb847 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -34,7 +34,7 @@ public static function setFactory(LoopDriverFactory $factory = null) { */ public static function execute(callable $callback, LoopDriver $driver = null) { - $driver = $driver ?: $this->createDriver(); + $driver = $driver ?: self::createDriver(); $previousRegistry = self::$registry; $previousDriver = self::$driver; From 30254b2a3601838b25dd157523c0f4d91bc46cee Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 15 May 2016 17:22:47 +0200 Subject: [PATCH 3/7] Change namespace of LoopDriverFactory --- src/LoopDriverFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LoopDriverFactory.php b/src/LoopDriverFactory.php index a9bb129..cfcaa81 100644 --- a/src/LoopDriverFactory.php +++ b/src/LoopDriverFactory.php @@ -1,6 +1,6 @@ Date: Sun, 15 May 2016 20:18:45 +0200 Subject: [PATCH 4/7] Check that factory returns an instance of LoopDriver --- src/Loop.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index eceb847..d29b989 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -54,7 +54,7 @@ public static function execute(callable $callback, LoopDriver $driver = null) /** * Create a new driver if a factory is present, otherwise throw. * - * @throws \LogicException if no factory is set + * @throws \LogicException if no factory is set or no driver returned from factory */ private static function createDriver() { @@ -62,7 +62,13 @@ private static function createDriver() throw new \LogicException("Can't create an event loop driver without a factory."); } - return self::$factory->create(); + $driver = self::$factory->create(); + + if (!$driver instanceof LoopDriver) { + throw new \LogicException("LoopDriverFactory didn't return a LoopDriver."); + } + + return $driver; } /** From 665cc7fc5b46e43a4caa5291a2ffd1e2aac824ae Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Wed, 18 May 2016 13:20:41 +0200 Subject: [PATCH 5/7] Instantiate driver if none exists upon Loop::setFactory to support sync waits --- src/Loop.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Loop.php b/src/Loop.php index d29b989..7825342 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -18,10 +18,12 @@ final class Loop /** * Set the factory to be used to create a driver if none is passed to - * self::execute. + * self::execute. A default driver will be created if none exists yet + * to support synchronous waits in traditional applications. */ public static function setFactory(LoopDriverFactory $factory = null) { self::$factory = $factory; + self::$driver = self::$driver ?: self::createDriver(); } /** From f890d37e80a403ca5c70e8536af6aeaa03a89d7f Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Thu, 19 May 2016 13:19:24 +0200 Subject: [PATCH 6/7] Use default registry to support sync wait, fix error messages --- src/Loop.php | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 7825342..222a41c 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -16,14 +16,24 @@ final class Loop */ private static $driver = null; + /** + * @var bool + */ + private static $running = false; + /** * Set the factory to be used to create a driver if none is passed to - * self::execute. A default driver will be created if none exists yet + * self::execute. A default driver will be created if none is running * to support synchronous waits in traditional applications. */ - public static function setFactory(LoopDriverFactory $factory = null) { + public static function setFactory(LoopDriverFactory $factory = null) + { self::$factory = $factory; - self::$driver = self::$driver ?: self::createDriver(); + + if (!self::$running) { + self::$driver = self::createDriver(); + self::$registry = []; + } } /** @@ -36,12 +46,14 @@ public static function setFactory(LoopDriverFactory $factory = null) { */ public static function execute(callable $callback, LoopDriver $driver = null) { - $driver = $driver ?: self::createDriver(); $previousRegistry = self::$registry; - $previousDriver = self::$driver; + + $driver = $driver ?: self::createDriver(); + self::$driver = $driver; self::$registry = []; + self::$running = true; try { $callback(); @@ -50,6 +62,7 @@ public static function execute(callable $callback, LoopDriver $driver = null) } finally { self::$driver = $previousDriver; self::$registry = $previousRegistry; + self::$running = false; } } @@ -67,7 +80,8 @@ private static function createDriver() $driver = self::$factory->create(); if (!$driver instanceof LoopDriver) { - throw new \LogicException("LoopDriverFactory didn't return a LoopDriver."); + $type = is_object($driver) ? "an instance of " . get_class($driver) : gettype($driver); + throw new \LogicException("Factory returned {$type}, but must return an instance of LoopDriver."); } return $driver; @@ -81,7 +95,7 @@ private static function createDriver() public static function get() { if (null === self::$driver) { - throw new \RuntimeException('Not within the scope of an event loop driver'); + throw new \RuntimeException('Missing driver; Neither in Loop::execute nor factory set.'); } return self::$driver; @@ -268,12 +282,16 @@ public static function setErrorHandler(callable $callback = null) * * @return bool */ - public static function supports($feature) { + public static function supports($feature) + { return self::get()->supports($feature); } /** * Disable construction as this is a static class. */ - private function __construct() {} + private function __construct() + { + // intentionally left blank + } } From 1c1e7403924b7f8ceb33115f92549e803863c388 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Thu, 19 May 2016 15:51:47 +0200 Subject: [PATCH 7/7] Improve factory error messages --- src/Loop.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 222a41c..64e2b7e 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -74,14 +74,14 @@ public static function execute(callable $callback, LoopDriver $driver = null) private static function createDriver() { if (self::$factory === null) { - throw new \LogicException("Can't create an event loop driver without a factory."); + throw new \LogicException("No loop driver factory set; Either pass a driver to Loop::execute or set a factory."); } $driver = self::$factory->create(); if (!$driver instanceof LoopDriver) { $type = is_object($driver) ? "an instance of " . get_class($driver) : gettype($driver); - throw new \LogicException("Factory returned {$type}, but must return an instance of LoopDriver."); + throw new \LogicException("Loop driver factory returned {$type}, but must return an instance of LoopDriver."); } return $driver;