update to PHP-8.1 master
authorMichael Wallner <mike@php.net>
Thu, 9 Jun 2022 21:27:33 +0000 (23:27 +0200)
committerMichael Wallner <mike@php.net>
Thu, 9 Jun 2022 21:28:53 +0000 (23:28 +0200)
42 files changed:
README.md
composer.json
examples/amploop.php
examples/cache.php
examples/cli.php
examples/examples.inc [new file with mode: 0644]
examples/generator.php
examples/gistlog.php
examples/hooks.php
examples/promise.php
examples/readme.php
examples/watchowned.php
http.stub.php [deleted file]
lib/API.php
lib/API/Call.php
lib/API/Call/Cache.php
lib/API/Call/Cache/Control.php
lib/API/Call/Cache/Service.php
lib/API/Call/Cache/Service/Hollow.php
lib/API/Call/Cache/Service/ItemPool.php
lib/API/Call/Cache/Service/Simple.php
lib/API/Call/Deferred.php
lib/API/Call/Result.php
lib/API/Consumer.php
lib/API/ContentType/Handler.php
lib/API/ContentType/Handler/Base64.php
lib/API/ContentType/Handler/Json.php
lib/API/ContentType/Handler/Stream.php
lib/API/ContentType/Handler/Text.php
lib/API/Future.php
lib/API/Future/Amp2.php [new file with mode: 0644]
lib/API/Future/Common.php [new file with mode: 0644]
lib/API/Future/React2.php [new file with mode: 0644]
lib/API/Future/functions.php
lib/API/Iterator.php [deleted file]
lib/API/Links.php
lib/API/Links/functions.php
lib/Exception/functions.php
lib/functions.php
tests/CacheTest.php
tests/ContentTypeTest.php
tests/bootstrap.php

index ca82ab313e3378e675d4fd5ae777f8cc9cc8e6ad..ffee664fe49f701e54b97247c19026e3550a9532 100644 (file)
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 [![Build Status](https://travis-ci.org/m6w6/seekat.svg)](https://travis-ci.org/m6w6/seekat)
 
-Fluent Github API access with PHP-7 and [ext-http](https://github.com/m6w6/ext-http).
+Fluent Github API access with [ext-http](https://github.com/m6w6/ext-http).
 
 Support for the following promise providers built in:
  * [ReactPHP](https://github.com/reactphp/promise)
index 0c7dab4a0c23668ba123fdc93a1204027004aec0..5d07e1193efb8b8fca56d90845e56efdfb020a5d 100644 (file)
     "minimum-stability": "dev",
     "prefer-stable": true,
     "require": {
-        "php": ">=7.2",
-        "ext-http": ">=3.2",
+        "php": ">=8.1",
+        "ext-http": ">=4.2",
         "ext-json": "*",
-        "psr/log": "^1.0",
-        "psr/cache": "^1.0",
-        "psr/simple-cache": "^1.0",
-        "rize/uri-template": "^0.3.3"
+        "psr/log": "^3",
+        "psr/cache": "^1",
+        "psr/simple-cache": "^1",
+        "rize/uri-template": "^0.3.4",
+        "monolog/monolog": "^3"
     },
     "require-dev": {
-        "php": "^8",
+        "php": ">=8.1",
         "amphp/amp": "^2",
         "react/promise": "^2",
-        "monolog/monolog": "*",
-        "phpunit/phpunit": "*",
+        "phpunit/phpunit": "^9",
         "squizlabs/php_codesniffer": "*",
         "phpcompatibility/php-compatibility": "*"
     }
index 1abbaa11e42d264dacaf4478607f1f6d49ea2bb2..9afda4c29b20a495fbb8564c5628247275563013 100755 (executable)
@@ -6,107 +6,113 @@ require_once __DIR__."/../vendor/autoload.php";
 use seekat\API;
 use Amp\Loop as AmpLoop;
 
-$log = new Monolog\Logger("seekat");
-$log->pushHandler((new Monolog\Handler\StreamHandler(STDERR))->setLevel(Monolog\Logger::INFO));
+$client = new http\Client("curl", "seekat");
+$client->configure([
+       "use_eventloop" => new class($client, AmpLoop::get()) implements http\Client\Curl\User {
 
-$cli = new http\Client("curl", "seekat");
-$cli->configure([
-       "use_eventloop" => new class($cli, AmpLoop::get()) implements http\Client\Curl\User {
+               /**
+                * Timeout ID
+                */
+               private ?string $timeout = null;
+               private \Closure $runcb;
 
-       private $driver;
-       private $timeout;
-       private $client;
-       private $runcb;
+               function __construct(private http\Client $client, private AmpLoop\Driver $driver) {
+               }
 
-       function __construct(http\Client $client, AmpLoop\Driver $driver) {
-               $this->client = $client;
-               $this->driver = $driver;
-       }
-       function init($run) {
-               $this->runcb = $run;
-       }
-       function run($socket = null, int $action = null) {
-               if ($socket) {
-                       $remaining = ($this->runcb)($this->client, $socket, $action);
-               } else {
-                       $remaining = ($this->runcb)($this->client);
+               function init($run) : void {
+                       $this->runcb = $run(...);
                }
 
-               if (!$remaining) {
-                       $this->done();
+               /**
+                * @param resource $socket
+                */
+               function run($socket = null, int $action = null) : void {
+                       if ($socket) {
+                               $remaining = ($this->runcb)($this->client, $socket, $action);
+                       } else {
+                               $remaining = ($this->runcb)($this->client);
+                       }
+
+                       if (!$remaining) {
+                               $this->done();
+                       }
                }
-       }
-       function once() {
-               if (!$this->driver->getInfo()["running"]) {
-                       $this->driver->run();
+               function once() : void {
+                       if (!$this->driver->getInfo()["running"]) {
+                               $this->driver->run();
+                       }
                }
-       }
-       function send() {
-               # unused
-               throw new BadMethodCallException(__FUNCTION__);
-       }
-       function wait(int $timeout_ms = null) {
-               # unused
-               throw new BadMethodCallException(__FUNCTION__);
-       }
-       function timer(int $timeout_ms = null) {
-               if ($this->timeout) {
-                       $this->driver->cancel($this->timeout);
+               function send() : never {
+                       # unused
+                       throw new BadMethodCallException(__FUNCTION__);
+               }
+               function wait(int $timeout_ms = null) : never {
+                       # unused
+                       throw new BadMethodCallException(__FUNCTION__);
                }
+               function timer(int $timeout_ms = null) : void {
+                       if ($this->timeout) {
+                               $this->driver->cancel($this->timeout);
+                       }
 
-               $this->timeout = $this->driver->delay($timeout_ms, function() {
-                       $this->run();
-               });
-       }
-       function done() {
-               if ($this->timeout) {
-                       $this->driver->cancel($this->timeout);
-                       $this->timeout = null;
+                       $this->timeout = $this->driver->delay($timeout_ms, function() {
+                               $this->run();
+                       });
                }
-       }
-       function socket($socket, int $poll) {
-               foreach ((array) $this->driver->getState((string) $socket) as $id) {
-                       $this->driver->disable($id);
+               function done() : void {
+                       if ($this->timeout) {
+                               $this->driver->cancel($this->timeout);
+                               $this->timeout = null;
+                       }
                }
-               switch ($poll) {
-               case self::POLL_NONE:
-                       break;
-               case self::POLL_IN:
-                       $id = $this->driver->onReadable($socket, function($id, $socket) {
-                               $this->run($socket, self::POLL_IN);
-                       });
-                       $this->driver->setState((string) $socket, $id);
-                       break;
-               case self::POLL_OUT:
-                       $id = $this->driver->onWritable($socket, function($id, $socket) {
-                               $this->run($socket, self::POLL_OUT);
-                       });
-                       $this->driver->setState((string) $socket, $id);
-                       break;
-               case self::POLL_INOUT:
-                       $id = [
-                               $this->driver->onReadable($socket, function($id, $socket) {
+
+               /**
+                * @param resource $socket
+                */
+               function socket($socket, int $poll) : void {
+                       foreach ((array) $this->driver->getState((string) $socket) as $id) {
+                               $this->driver->disable($id);
+                       }
+                       switch ($poll) {
+                       case self::POLL_NONE:
+                               break;
+                       case self::POLL_IN:
+                               $id = $this->driver->onReadable($socket, function($id, $socket) {
                                        $this->run($socket, self::POLL_IN);
-                               }),
-                               $this->driver->onWritable($socket, function($id, $socket) {
+                               });
+                               $this->driver->setState((string) $socket, $id);
+                               break;
+                       case self::POLL_OUT:
+                               $id = $this->driver->onWritable($socket, function($id, $socket) {
                                        $this->run($socket, self::POLL_OUT);
-                               })
-                       ];
-                       $this->driver->setState((string) $socket, $id);
-                       break;
-               case self::POLL_REMOVE:
-                       foreach ((array) $this->driver->getState((string) $socket) as $id) {
-                               $this->driver->cancel($id);
+                               });
+                               $this->driver->setState((string) $socket, $id);
+                               break;
+                       case self::POLL_INOUT:
+                               $id = [
+                                       $this->driver->onReadable($socket, function($id, $socket) {
+                                               $this->run($socket, self::POLL_IN);
+                                       }),
+                                       $this->driver->onWritable($socket, function($id, $socket) {
+                                               $this->run($socket, self::POLL_OUT);
+                                       })
+                               ];
+                               $this->driver->setState((string) $socket, $id);
+                               break;
+                       case self::POLL_REMOVE:
+                               foreach ((array) $this->driver->getState((string) $socket) as $id) {
+                                       $this->driver->cancel($id);
+                               }
+                               $this->driver->setState((string) $socket, null);
+                               break;
                        }
-                       $this->driver->setState((string) $socket, null);
-                       break;
                }
        }
-}]);
+]);
+
+$future = API\Future\amp();
 
-$api = new API(API\Future\amp(), [
-       "Authorization" => "token ".getenv("GITHUB_TOKEN")
-], null, $cli, $log);
+$api = include "examples.inc";
 
 AmpLoop::run(function() use($api) {
        list($m6w6, $seekat) = yield [$api->users->m6w6(), $api->repos->m6w6->seekat()];
index c71af446c10ae63d2d23b98b6a359e6db2c0c5ef..dea3ab970c00ae0a89667d60cdc652af5b833973 100755 (executable)
@@ -1,25 +1,16 @@
 #!/usr/bin/env php
 <?php
 
-require __DIR__."/../vendor/autoload.php";
-
-use Monolog\{
-       Handler\StreamHandler, Logger
-};
-
-$log = new Logger("seekat");
-$log->pushHandler(new StreamHandler(STDERR, Logger::INFO));
+require_once __DIR__ . "/../vendor/autoload.php";
 
 $redis = new Redis;
 $redis->connect("localhost");
 $redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
 $cache = new class($redis) implements \seekat\API\Call\Cache\Service {
-       private $redis;
-       function __construct(Redis $redis) {
-               $this->redis = $redis;
+       function __construct(private readonly Redis $redis) {
        }
-       function clear() {
-               return $this->redis->flushDB();
+       function clear() : void {
+               $this->redis->flushDB();
        }
        function fetch(string $key, \http\Client\Response &$response = null): bool {
                list($exists, $response) = $this->redis
@@ -32,17 +23,17 @@ $cache = new class($redis) implements \seekat\API\Call\Cache\Service {
        function store(string $key, \http\Client\Response $response): bool {
                return $this->redis->set($key, $response);
        }
-       function del(string $key) {
-               return $this->redis->delete($key);
+       function del(string $key) : void {
+               $this->redis->del($key);
        }
 };
 
-$api = new seekat\API(seekat\API\Future\react(), [
-       "Authorization" => "token ".getenv("GITHUB_TOKEN")
-], null, null, $log, $cache);
+$log_level = "INFO";
+
+$api = include "examples.inc";
 
 $api(function($api) use($cache) {
        yield $api->users->m6w6();
        yield $api->users->m6w6();
-       $cache->clear();
+       //$cache->clear();
 });
index caae47c17d0c802b468a60bf5cb15f4b00364556..6da88150cbe9e7ab5da089feefb4a36a46eb1c5b 100755 (executable)
@@ -1,11 +1,8 @@
 #!/usr/bin/env php
 <?php
 
-require_once __DIR__."/../vendor/autoload.php";
+$api = include "examples.inc";
 
-$api = new seekat\API(seekat\API\Future\react(), [
-       "Authorization" => "token ".getenv("GITHUB_TOKEN")
-]);
 array_shift($argv);
 
 ($self = function($api) use(&$self) {
diff --git a/examples/examples.inc b/examples/examples.inc
new file mode 100644 (file)
index 0000000..2d150dc
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+use seekat\API;
+
+require_once __DIR__."/../vendor/autoload.php";
+
+$log_level = Monolog\Level::fromName(getenv("LOG_LEVEL") ?: "WARNING");
+
+return new API(
+       future: $future ?? API\Future\any(),
+       headers: $headers ?? API\auth("token", getenv("GITHUB_TOKEN")),
+       client: $client ?? new http\Client("curl", "seekat"),
+       logger: $logger ?? (new Monolog\Logger("seekat"))
+               ->pushHandler(new Monolog\Handler\StreamHandler(STDERR, $log_level)),
+       cache: $cache ?? new API\Call\Cache\Service\Hollow
+);
index 88b69cd004c9eddc6bd2e1b84520f0cfec7def8f..223c1e3dc7c84c642be19ffb43d3857a30e4d07f 100755 (executable)
@@ -1,19 +1,9 @@
 #!/usr/bin/env php
 <?php
 
-require_once __DIR__."/../vendor/autoload.php";
-
-use seekat\API;
 use seekat\API\Links;
 
-$log = new Monolog\Logger("seekat");
-$log->pushHandler((new Monolog\Handler\StreamHandler(STDERR))->setLevel(Monolog\Logger::INFO));
-
-$cli = new http\Client("curl", "seekat");
-
-$api = new API(API\Future\amp(), [
-       "Authorization" => "token ".getenv("GITHUB_TOKEN")
-], null, $cli, $log);
+$api = include "examples.inc";
 
 $api(function($api) {
        $count = 0;
index 6cdbe23faa070576085c585c34b79b013f19fe51..43d4ce1f44781f1b9cbaf747c832cd3191cacd59 100755 (executable)
@@ -1,17 +1,6 @@
 #!/usr/bin/env php
 <?php
-
-require __DIR__."/../vendor/autoload.php";
-
-
-$log = new Monolog\Logger("seekat");
-$log->pushHandler(new Monolog\Handler\StreamHandler(STDERR, Monolog\Logger::WARNING));
-
-$api = new seekat\API(
-       seekat\API\Future\react(),
-       seekat\API\auth("token", getenv("GITHUB_TOKEN")),
-       null, null, $log
-);
+$api = include "examples.inc";
 
 $api(function($api) {
        $gists = yield $api->users->m6w6->gists();
index 612e6de75dbfc014f7ac97daaf11a7152896e50a..fdeca097cb281c0921e596115c5ac0bfec2bd985 100755 (executable)
@@ -3,20 +3,15 @@
 
 require_once __DIR__."/../vendor/autoload.php";
 
-use seekat\{API, API\Future, API\Links};
-use Monolog\{Logger, Handler};
+use seekat\API\Links;
 
-$cli = new http\Client("curl", "seekat");
-$cli->configure([
+$client = new http\Client("curl", "seekat");
+$client->configure([
        "max_host_connections" => 10,
        "max_total_connections" => 50,
        "use_eventloop" => true,
 ]);
-
-$log = new Logger("seekat");
-$log->pushHandler(new Handler\StreamHandler(STDERR, Logger::NOTICE));
-
-$api = new API(Future\react(), API\auth("token", getenv("GITHUB_TOKEN")), null, $cli, $log);
+$api = include "examples.inc";
 
 $api(function() use($api) {
        $repos = yield $api->users->m6w6->repos([
index e1f5b9d4fbd4a3311e322fe2706d6ffa11423928..b39890d8d51158bc21af4f350dd57724dd9c0973 100755 (executable)
@@ -1,11 +1,7 @@
 #!/usr/bin/env php
 <?php
 
-require_once __DIR__."/../vendor/autoload.php";
-
-use seekat\API;
-
-$api = new API(API\Future\amp(), API\auth("token", getenv("GITHUB_TOKEN")));
+$api = include "examples.inc";
 
 $api->users->m6w6->gists()->onResolve(function($error, $gists) {
        $error and die($error);
@@ -17,7 +13,7 @@ $api->users->m6w6->gists()->onResolve(function($error, $gists) {
                                        printf("\nGist %s, %s:\n", $gist->id, $gist->description ?: "<no title>");
                                }
                                $cs = $commit->change_status;
-                               printf("\t%s: ", substr($commit->version,0,8));
+                               printf("\t%s: ", substr($commit->version, 0, 8));
                                printf("-%s+%s=%s\n", $cs->deletions, $cs->additions, $cs->total);
                        }
                });
index f7b6b57500e2d2c8d16fc8641b01011b71a99a2c..0aea554e279dcae130949d27f4b520d9eff1ca38 100755 (executable)
@@ -1,8 +1,7 @@
 #!/usr/bin/env php
 <?php
 
-require_once __DIR__."/../vendor/autoload.php";
-
-(new seekat\API(seekat\API\Future\amp()))(function($api) {
+$api = include "examples.inc";
+$api(function($api) {
        echo yield $api->repos->m6w6->seekat->readme->as("raw")->get();
 });
index d1ff87969c60eeae224d3eff466fbd2b05492436..cffcc2b3298b8c16b7c72e1b8dfa26b36002d590 100755 (executable)
@@ -1,23 +1,9 @@
 #!/usr/bin/env php
 <?php
 
-use http\Client;
-use Monolog\Handler\StreamHandler;
-use Monolog\Logger;
-use seekat\API;
 use seekat\API\Links;
 
-require_once __DIR__."/../vendor/autoload.php";
-
-$log = new Monolog\Logger("seekat");
-$log->pushHandler((new Monolog\Handler\StreamHandler(STDERR))
-       ->setLevel(Monolog\Logger::WARNING));
-
-$cli = new http\Client("curl", "seekat");
-
-$api = new API(API\Future\amp(), [
-       "Authorization" => "token ".getenv("GITHUB_TOKEN")
-], null, $cli, $log);
+$api = include "examples.inc";
 
 $api(function($api) {
        $count = 0;
diff --git a/http.stub.php b/http.stub.php
deleted file mode 100644 (file)
index 7a114c9..0000000
+++ /dev/null
@@ -1,3424 +0,0 @@
-<?php
-/**
- * Extended HTTP support. Again.
- * 
- * * Introduces the http namespace.
- * * PHP stream based message bodies.
- * * Encapsulated env request/response.
- * * Modular client support.
- */
-namespace http;
-use http;
-/**
- * The HTTP client. See http\Client\Curl's [options](http/Client/Curl#Options:) which is the only driver currently supported.
- */
-class Client implements \SplSubject, \Countable {
-       /**
-        * Debug callback's $data contains human readable text.
-        */
-       const DEBUG_INFO = 0;
-       /**
-        * Debug callback's $data contains data received.
-        */
-       const DEBUG_IN = 1;
-       /**
-        * Debug callback's $data contains data sent.
-        */
-       const DEBUG_OUT = 2;
-       /**
-        * Debug callback's $data contains headers.
-        */
-       const DEBUG_HEADER = 16;
-       /**
-        * Debug callback's $data contains a body part.
-        */
-       const DEBUG_BODY = 32;
-       /**
-        * Debug callback's $data contains SSL data.
-        */
-       const DEBUG_SSL = 64;
-       /**
-        * Attached observers.
-        * 
-        * @private
-        * @var \SplObjectStorage
-        */
-       private $observers = NULL;
-       /**
-        * Set options.
-        * 
-        * @protected
-        * @var array
-        */
-       protected $options = NULL;
-       /**
-        * Request/response history.
-        * 
-        * @protected
-        * @var \http\Message
-        */
-       protected $history = NULL;
-       /**
-        * Whether to record history in http\Client::$history.
-        * 
-        * @public
-        * @var bool
-        */
-       public $recordHistory = false;
-       /**
-        * Create a new HTTP client.
-        * 
-        * Currently only "curl" is supported as a $driver, and used by default.
-        * Persisted resources identified by $persistent_handle_id will be re-used if available.
-        * 
-        * @param string $driver The HTTP client driver to employ. Currently only the default driver, "curl", is supported.
-        * @param string $persistent_handle_id If supplied, created curl handles will be persisted with this identifier for later reuse.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @throws \http\Exception\RuntimeException
-        */
-       function __construct(string $driver = NULL, string $persistent_handle_id = NULL) {}
-       /**
-        * Add custom cookies.
-        * See http\Client::setCookies().
-        * 
-        * @param array $cookies Custom cookies to add.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client self.
-        */
-       function addCookies(array $cookies = NULL) {}
-       /**
-        * Add specific SSL options.
-        * See http\Client::setSslOptions(), http\Client::setOptions() and http\Client\Curl\$ssl options.
-        * 
-        * @param array $ssl_options Add this SSL options.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client self.
-        */
-       function addSslOptions(array $ssl_options = NULL) {}
-       /**
-        * Implements SplSubject. Attach another observer.
-        * Attached observers will be notified with progress of each transfer.
-        * 
-        * @param \SplObserver $observer An implementation of SplObserver.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client self.
-        */
-       function attach(\SplObserver $observer) {}
-       /**
-        * Configure the client's low level options.
-        * 
-        * > ***NOTE:***
-        * > This method has been added in v2.3.0.
-        * 
-        * @param array $configuration Key/value pairs of low level options.
-        *    See f.e. the [configuration options for the Curl driver](http/Client/Curl#Configuration:).
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client self.
-        */
-       function configure(array $configuration) {}
-       /**
-        * Implements Countable. Retrieve the number of enqueued requests.
-        * 
-        * > ***NOTE:***
-        * > The enqueued requests are counted without regard whether they are finished or not.
-        * 
-        * @return int number of enqueued requests.
-        */
-       function count() {}
-       /**
-        * Dequeue the http\Client\Request $request.
-        * 
-        * See http\Client::requeue(), if you want to requeue the request, instead of calling http\Client::dequeue() and then http\Client::enqueue().
-        * 
-        * @param \http\Client\Request $request The request to cancel.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @throws \http\Exception\RuntimeException
-        * @return \http\Client self.
-        */
-       function dequeue(\http\Client\Request $request) {}
-       /**
-        * Implements SplSubject. Detach $observer, which has been previously attached.
-        * 
-        * @param \SplObserver $observer Previously attached instance of SplObserver implementation.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client self.
-        */
-       function detach(\SplObserver $observer) {}
-       /**
-        * Enable usage of an event library like libevent, which might improve performance with big socket sets.
-        * 
-        * > ***NOTE:***
-        * > This method has been deprecated in 2.3.0, please use http\Client::configure() instead.
-        * 
-        * @param bool $enable Whether to enable libevent usage.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client self.
-        * @deprecated
-        */
-       function enableEvents(bool $enable = true) {}
-       /**
-        * Enable sending pipelined requests to the same host if the driver supports it.
-        * 
-        * > ***NOTE:***
-        * > This method has been deprecated in 2.3.0, please use http\Client::configure() instead.
-        * 
-        * @param bool $enable Whether to enable pipelining.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client self.
-        * @deprecated
-        */
-       function enablePipelining(bool $enable = true) {}
-       /**
-        * Add another http\Client\Request to the request queue.
-        * If the optional callback $cb returns true, the request will be automatically dequeued.
-        * 
-        * > ***Note:***
-        * > The http\Client\Response object resulting from the request is always stored
-        * > internally to be retrieved at a later time, __even__ when $cb is used.
-        * >
-        * > If you are about to send a lot of requests and do __not__ need the response
-        * > after executing the callback, you can use http\Client::getResponse() within
-        * > the callback to keep the memory usage level as low as possible.
-        * 
-        * See http\Client::dequeue() and http\Client::send().
-        * 
-        * @param \http\Client\Request $request The request to enqueue.
-        * @param callable $cb as function(\http\Response $response) : ?bool
-        *   A callback to automatically call when the request has finished.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @throws \http\Exception\RuntimeException
-        * @return \http\Client self.
-        */
-       function enqueue(\http\Client\Request $request, callable $cb = NULL) {}
-       /**
-        * Get a list of available configuration options and their default values.
-        * 
-        * See f.e. the [configuration options for the Curl driver](http/Client/Curl#Configuration:).
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @return array list of key/value pairs of available configuration options and their default values.
-        */
-       function getAvailableConfiguration() {}
-       /**
-        * List available drivers.
-        * 
-        * @return array list of supported drivers.
-        */
-       function getAvailableDrivers() {}
-       /**
-        * Retrieve a list of available request options and their default values.
-        * 
-        * See f.e. the [request options for the Curl driver](http/Client/Curl#Options:).
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @return array list of key/value pairs of available request options and their default values.
-        */
-       function getAvailableOptions() {}
-       /**
-        * Get priorly set custom cookies.
-        * See http\Client::setCookies().
-        * 
-        * @return array custom cookies.
-        */
-       function getCookies() {}
-       /**
-        * Simply returns the http\Message chain representing the request/response history.
-        * 
-        * > ***NOTE:***
-        * > The history is only recorded while http\Client::$recordHistory is true.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Message the request/response message chain representing the client's history.
-        */
-       function getHistory() {}
-       /**
-        * Returns the SplObjectStorage holding attached observers.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \SplObjectStorage observer storage.
-        */
-       function getObservers() {}
-       /**
-        * Get priorly set options.
-        * See http\Client::setOptions().
-        * 
-        * @return array options.
-        */
-       function getOptions() {}
-       /**
-        * Retrieve the progress information for $request.
-        * 
-        * @param \http\Client\Request $request The request to retrieve the current progress information for.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return object|NULL object stdClass instance holding progress information.
-        *               or NULL if $request is not enqueued.
-        */
-       function getProgressInfo(\http\Client\Request $request) {}
-       /**
-        * Retrieve the corresponding response of an already finished request, or the last received response if $request is not set.
-        * 
-        * > ***NOTE:***
-        * > If $request is NULL, then the response is removed from the internal storage (stack-like operation).
-        * 
-        * @param \http\Client\Request $request The request to fetch the stored response for.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client\Response|NULL \http\Client\Response the stored response for the request, or the last that was received.
-        *               or NULL if no more response was available to pop, when no $request was given.
-        */
-       function getResponse(\http\Client\Request $request = NULL) {}
-       /**
-        * Retrieve priorly set SSL options.
-        * See http\Client::getOptions() and http\Client::setSslOptions().
-        * 
-        * @return array SSL options.
-        */
-       function getSslOptions() {}
-       /**
-        * Get transfer related information for a running or finished request.
-        * 
-        * @param \http\Client\Request $request The request to probe for transfer info.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return object stdClass instance holding transfer related information.
-        */
-       function getTransferInfo(\http\Client\Request $request) {}
-       /**
-        * Implements SplSubject. Notify attached observers about progress with $request.
-        * 
-        * @param \http\Client\Request $request The request to notify about.
-        * @param object $progress stdClass instance holding progress information.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client self.
-        */
-       function notify(\http\Client\Request $request = NULL, $progress = NULL) {}
-       /**
-        * Perform outstanding transfer actions.
-        * See http\Client::wait() for the completing interface.
-        * 
-        * @return bool true if there are more transfers to complete.
-        */
-       function once() {}
-       /**
-        * Requeue an http\Client\Request.
-        * 
-        * The difference simply is, that this method, in contrast to http\Client::enqueue(), does not throw an http\Exception when the request to queue is already enqueued and dequeues it automatically prior enqueueing it again.
-        * 
-        * @param \http\Client\Request $request The request to queue.
-        * @param callable $cb as function(\http\Response $response) : ?bool
-        *   A callback to automatically call when the request has finished.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        * @return \http\Client self.
-        */
-       function requeue(\http\Client\Request $request, callable $cb = NULL) {}
-       /**
-        * Reset the client to the initial state.
-        * 
-        * @return \http\Client self.
-        */
-       function reset() {}
-       /**
-        * Send all enqueued requests.
-        * See http\Client::once() and http\Client::wait() for a more fine grained interface.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        * @return \http\Client self.
-        */
-       function send() {}
-       /**
-        * Set custom cookies.
-        * See http\Client::addCookies() and http\Client::getCookies().
-        * 
-        * @param array $cookies Set the custom cookies to this array.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client self.
-        */
-       function setCookies(array $cookies = NULL) {}
-       /**
-        * Set client debugging callback.
-        * 
-        * > ***NOTE:***
-        * > This method has been added in v2.6.0, resp. v3.1.0.
-        * 
-        * @param callable $callback as function(http\Client $c, http\Client\Request $r, int $type, string $data)
-        *   The debug callback. For $type see http\Client::DEBUG_* constants.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client self.
-        */
-       function setDebug(callable $callback) {}
-       /**
-        * Set client options.
-        * See http\Client\Curl.
-        * 
-        * > ***NOTE:***
-        * > Only options specified prior enqueueing a request are applied to the request.
-        * 
-        * @param array $options The options to set.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client self.
-        */
-       function setOptions(array $options = NULL) {}
-       /**
-        * Specifically set SSL options.
-        * See http\Client::setOptions() and http\Client\Curl\$ssl options.
-        * 
-        * @param array $ssl_options Set SSL options to this array.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client self.
-        */
-       function setSslOptions(array $ssl_options = NULL) {}
-       /**
-        * Wait for $timeout seconds for transfers to provide data.
-        * This is the completion call to http\Client::once().
-        * 
-        * @param float $timeout Seconds to wait for data on open sockets.
-        * @return bool success.
-        */
-       function wait(float $timeout = 0) {}
-}
-/**
- * A class representing a list of cookies with specific attributes.
- */
-class Cookie  {
-       /**
-        * Do not decode cookie contents.
-        */
-       const PARSE_RAW = 1;
-       /**
-        * The cookies' flags have the secure attribute set.
-        */
-       const SECURE = 16;
-       /**
-        * The cookies' flags have the httpOnly attribute set.
-        */
-       const HTTPONLY = 32;
-       /**
-        * Create a new cookie list.
-        * 
-        * @param mixed $cookies The string or list of cookies to parse or set.
-        * @param int $flags Parse flags. See http\Cookie::PARSE_* constants.
-        * @param array $allowed_extras List of extra attribute names to recognize.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        */
-       function __construct($cookies = NULL, int $flags = 0, array $allowed_extras = NULL) {}
-       /**
-        * String cast handler. Alias of http\Cookie::toString().
-        * 
-        * @return string the cookie(s) represented as string.
-        */
-       function __toString() {}
-       /**
-        * Add a cookie.
-        * See http\Cookie::setCookie() and http\Cookie::addCookies().
-        * 
-        * @param string $cookie_name The key of the cookie.
-        * @param string $cookie_value The value of the cookie.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function addCookie(string $cookie_name, string $cookie_value) {}
-       /**
-        * (Re)set the cookies.
-        * See http\Cookie::setCookies().
-        * 
-        * @param array $cookies Add cookies of this array of form ["name" => "value"].
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function addCookies(array $cookies) {}
-       /**
-        * Add an extra attribute to the cookie list.
-        * See http\Cookie::setExtra().
-        * 
-        * @param string $extra_name The key of the extra attribute.
-        * @param string $extra_value The value of the extra attribute.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function addExtra(string $extra_name, string $extra_value) {}
-       /**
-        * Add several extra attributes.
-        * See http\Cookie::addExtra().
-        * 
-        * @param array $extras A list of extra attributes of the form ["key" => "value"].
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function addExtras(array $extras) {}
-       /**
-        * Retrieve a specific cookie value.
-        * See http\Cookie::setCookie().
-        * 
-        * @param string $cookie_name The key of the cookie to look up.
-        * @return string|NULL string the cookie value.
-        *               or NULL if $cookie_name could not be found.
-        */
-       function getCookie(string $cookie_name) {}
-       /**
-        * Get the list of cookies.
-        * See http\Cookie::setCookies().
-        * 
-        * @return array the list of cookies of form ["name" => "value"].
-        */
-       function getCookies() {}
-       /**
-        * Retrieve the effective domain of the cookie list.
-        * See http\Cookie::setDomain().
-        * 
-        * @return string the effective domain.
-        */
-       function getDomain() {}
-       /**
-        * Get the currently set expires attribute.
-        * See http\Cookie::setExpires().
-        * 
-        * > ***NOTE:***
-        * > A return value of -1 means that the attribute is not set.
-        * 
-        * @return int the currently set expires attribute as seconds since the epoch.
-        */
-       function getExpires() {}
-       /**
-        * Retrieve an extra attribute.
-        * See http\Cookie::setExtra().
-        * 
-        * @param string $name The key of the extra attribute.
-        * @return string the value of the extra attribute.
-        */
-       function getExtra(string $name) {}
-       /**
-        * Retrieve the list of extra attributes.
-        * See http\Cookie::setExtras().
-        * 
-        * @return array the list of extra attributes of the form ["key" => "value"].
-        */
-       function getExtras() {}
-       /**
-        * Get the currently set flags.
-        * See http\Cookie::SECURE and http\Cookie::HTTPONLY constants.
-        * 
-        * @return int the currently set flags bitmask.
-        */
-       function getFlags() {}
-       /**
-        * Get the currently set max-age attribute of the cookie list.
-        * See http\Cookie::setMaxAge().
-        * 
-        * > ***NOTE:***
-        * > A return value of -1 means that the attribute is not set.
-        * 
-        * @return int the currently set max-age.
-        */
-       function getMaxAge() {}
-       /**
-        * Retrieve the path the cookie(s) of this cookie list are effective at.
-        * See http\Cookie::setPath().
-        * 
-        * @return string the effective path.
-        */
-       function getPath() {}
-       /**
-        * (Re)set a cookie.
-        * See http\Cookie::addCookie() and http\Cookie::setCookies().
-        * 
-        * > ***NOTE:***
-        * > The cookie will be deleted from the list if $cookie_value is NULL.
-        * 
-        * @param string $cookie_name The key of the cookie.
-        * @param string $cookie_value The value of the cookie.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setCookie(string $cookie_name, string $cookie_value) {}
-       /**
-        * (Re)set the cookies.
-        * See http\Cookie::addCookies().
-        * 
-        * @param array $cookies Set the cookies to this array.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setCookies(array $cookies = NULL) {}
-       /**
-        * Set the effective domain of the cookie list.
-        * See http\Cookie::setPath().
-        * 
-        * @param string $value The domain the cookie(s) belong to.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setDomain(string $value = NULL) {}
-       /**
-        * Set the traditional expires timestamp.
-        * See http\Cookie::setMaxAge() for a safer alternative.
-        * 
-        * @param int $value The expires timestamp as seconds since the epoch.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setExpires(int $value = -1) {}
-       /**
-        * (Re)set an extra attribute.
-        * See http\Cookie::addExtra().
-        * 
-        * > ***NOTE:***
-        * > The attribute will be removed from the extras list if $extra_value is NULL.
-        * 
-        * @param string $extra_name The key of the extra attribute.
-        * @param string $extra_value The value of the extra attribute.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setExtra(string $extra_name, string $extra_value = NULL) {}
-       /**
-        * (Re)set the extra attributes.
-        * See http\Cookie::addExtras().
-        * 
-        * @param array $extras Set the extra attributes to this array.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setExtras(array $extras = NULL) {}
-       /**
-        * Set the flags to specified $value.
-        * See http\Cookie::SECURE and http\Cookie::HTTPONLY constants.
-        * 
-        * @param int $value The new flags bitmask.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setFlags(int $value = 0) {}
-       /**
-        * Set the maximum age the cookie may have on the client side.
-        * This is a client clock departure safe alternative to the "expires" attribute.
-        * See http\Cookie::setExpires().
-        * 
-        * @param int $value The max-age in seconds.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setMaxAge(int $value = -1) {}
-       /**
-        * Set the path the cookie(s) of this cookie list should be effective at.
-        * See http\Cookie::setDomain().
-        * 
-        * @param string $path The URL path the cookie(s) should take effect within.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Cookie self.
-        */
-       function setPath(string $path = NULL) {}
-       /**
-        * Get the cookie list as array.
-        * 
-        * @return array the cookie list as array.
-        */
-       function toArray() {}
-       /**
-        * Retrieve the string representation of the cookie list.
-        * See http\Cookie::toArray().
-        * 
-        * @return string the cookie list as string.
-        */
-       function toString() {}
-}
-/**
- * 
- */
-namespace http\Encoding;
-namespace http;
-/**
- * The http\Env class provides static methods to manipulate and inspect the server's current request's HTTP environment.
- */
-class Env  {
-       /**
-        * Retrieve the current HTTP request's body.
-        * 
-        * @param string $body_class_name A user class extending http\Message\Body.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Message\Body instance representing the request body
-        */
-       function getRequestBody(string $body_class_name = NULL) {}
-       /**
-        * Retrieve one or all headers of the current HTTP request.
-        * 
-        * @param string $header_name The key of a header to retrieve.
-        * @return NULL|string|array NULL if $header_name was not found
-        *               or string the compound header when $header_name was found
-        *               or array of all headers if $header_name was not specified
-        */
-       function getRequestHeader(string $header_name = NULL) {}
-       /**
-        * Get the HTTP response code to send.
-        * 
-        * @return int the HTTP response code.
-        */
-       function getResponseCode() {}
-       /**
-        * Get one or all HTTP response headers to be sent.
-        * 
-        * @param string $header_name The name of the response header to retrieve.
-        * @return string|NULL|array string the compound value of the response header to send
-        *               or NULL if the header was not found
-        *               or array of all response headers, if $header_name was not specified
-        */
-       function getResponseHeader(string $header_name = NULL) {}
-       /**
-        * Retrieve a list of all known HTTP response status.
-        * 
-        * @return array mapping of the form \[
-        *   ...
-        *   int $code => string $status
-        *   ...
-        *   \]
-        */
-       function getResponseStatusForAllCodes() {}
-       /**
-        * Retrieve the string representation of specified HTTP response code.
-        * 
-        * @param int $code The HTTP response code to get the string representation for.
-        * @return string the HTTP response status message (may be empty, if no message for this code was found)
-        */
-       function getResponseStatusForCode(int $code) {}
-       /**
-        * Generic negotiator. For specific client negotiation see http\Env::negotiateContentType() and related methods.
-        * 
-        * > ***NOTE:***
-        * > The first element of $supported serves as a default if no operand matches.
-        * 
-        * @param string $params HTTP header parameter's value to negotiate.
-        * @param array $supported List of supported negotiation operands.
-        * @param string $prim_typ_sep A "primary type separator", i.e. that would be a hyphen for content language negotiation (en-US, de-DE, etc.).
-        * @param array $result Out parameter recording negotiation results.
-        * @return NULL|string NULL if negotiation fails.
-        *               or string the closest match negotiated, or the default (first entry of $supported).
-        */
-       function negotiate(string $params, array $supported, string $prim_typ_sep = NULL, array &$result = NULL) {}
-       /**
-        * Negotiate the client's preferred character set.
-        * 
-        * > ***NOTE:***
-        * > The first element of $supported character sets serves as a default if no character set matches.
-        * 
-        * @param array $supported List of supported content character sets.
-        * @param array $result Out parameter recording negotiation results.
-        * @return NULL|string NULL if negotiation fails.
-        *               or string the negotiated character set.
-        */
-       function negotiateCharset(array $supported, array &$result = NULL) {}
-       /**
-        * Negotiate the client's preferred MIME content type.
-        * 
-        * > ***NOTE:***
-        * > The first element of $supported content types serves as a default if no content-type matches.
-        * 
-        * @param array $supported List of supported MIME content types.
-        * @param array $result Out parameter recording negotiation results.
-        * @return NULL|string NULL if negotiation fails.
-        *               or string the negotiated content type.
-        */
-       function negotiateContentType(array $supported, array &$result = NULL) {}
-       /**
-        * Negotiate the client's preferred encoding.
-        * 
-        * > ***NOTE:***
-        * > The first element of $supported encodings serves as a default if no encoding matches.
-        * 
-        * @param array $supported List of supported content encodings.
-        * @param array $result Out parameter recording negotiation results.
-        * @return NULL|string NULL if negotiation fails.
-        *               or string the negotiated encoding.
-        */
-       function negotiateEncoding(array $supported, array &$result = NULL) {}
-       /**
-        * Negotiate the client's preferred language.
-        * 
-        * > ***NOTE:***
-        * > The first element of $supported languages serves as a default if no language matches.
-        * 
-        * @param array $supported List of supported content languages.
-        * @param array $result Out parameter recording negotiation results.
-        * @return NULL|string NULL if negotiation fails.
-        *               or string the negotiated language.
-        */
-       function negotiateLanguage(array $supported, array &$result = NULL) {}
-       /**
-        * Set the HTTP response code to send.
-        * 
-        * @param int $code The HTTP response status code.
-        * @return bool Success.
-        */
-       function setResponseCode(int $code) {}
-       /**
-        * Set a response header, either replacing a prior set header, or appending the new header value, depending on $replace.
-        * 
-        * If no $header_value is specified, or $header_value is NULL, then a previously set header with the same key will be deleted from the list.
-        * 
-        * If $response_code is not 0, the response status code is updated accordingly.
-        * 
-        * @param string $header_name
-        * @param mixed $header_value
-        * @param int $response_code
-        * @param bool $replace
-        * @return bool Success.
-        */
-       function setResponseHeader(string $header_name, $header_value = NULL, int $response_code = NULL, bool $replace = NULL) {}
-}
-/**
- * The http extension's Exception interface.
- * 
- * Use it to catch any Exception thrown by pecl/http.
- * 
- * The individual exception classes extend their equally named native PHP extensions, if such exist, and implement this empty interface. For example the http\Exception\BadMethodCallException extends SPL's BadMethodCallException.
- */
-interface Exception  {
-}
-/**
- * The http\Header class provides methods to manipulate, match, negotiate and serialize HTTP headers.
- */
-class Header implements \Serializable {
-       /**
-        * None of the following match constraints applies.
-        */
-       const MATCH_LOOSE = 0;
-       /**
-        * Perform case sensitive matching.
-        */
-       const MATCH_CASE = 1;
-       /**
-        * Match only on word boundaries (according by CType alpha-numeric).
-        */
-       const MATCH_WORD = 16;
-       /**
-        * Match the complete string.
-        */
-       const MATCH_FULL = 32;
-       /**
-        * Case sensitively match the full string (same as MATCH_CASE|MATCH_FULL).
-        */
-       const MATCH_STRICT = 33;
-       /**
-        * The name of the HTTP header.
-        * 
-        * @public
-        * @var string
-        */
-       public $name = NULL;
-       /**
-        * The value of the HTTP header.
-        * 
-        * @public
-        * @var mixed
-        */
-       public $value = NULL;
-       /**
-        * Create an http\Header instance for use of simple matching or negotiation. If the value of the header is an array it may be compounded to a single comma separated string.
-        * 
-        * @param string $name The HTTP header name.
-        * @param mixed $value The value of the header.
-        * 
-        * # Throws:
-        */
-       function __construct(string $name = NULL, $value = NULL) {}
-       /**
-        * String cast handler. Alias of http\Header::serialize().
-        * 
-        * @return string the serialized form of the HTTP header (i.e. "Name: value").
-        */
-       function __toString() {}
-       /**
-        * Create a parameter list out of the HTTP header value.
-        * 
-        * @param mixed $ps The parameter separator(s).
-        * @param mixed $as The argument separator(s).
-        * @param mixed $vs The value separator(s).
-        * @param int $flags The modus operandi. See http\Params constants.
-        * @return \http\Params instance
-        */
-       function getParams($ps = NULL, $as = NULL, $vs = NULL, int $flags = NULL) {}
-       /**
-        * Match the HTTP header's value against provided $value according to $flags.
-        * 
-        * @param string $value The comparison value.
-        * @param int $flags The modus operandi. See http\Header constants.
-        * @return bool whether $value matches the header value according to $flags.
-        */
-       function match(string $value, int $flags = NULL) {}
-       /**
-        * Negotiate the header's value against a list of supported values in $supported.
-        * Negotiation operation is adopted according to the header name, i.e. if the
-        * header being negotiated is Accept, then a slash is used as primary type
-        * separator, and if the header is Accept-Language respectively, a hyphen is
-        * used instead.
-        * 
-        * > ***NOTE:***
-        * > The first element of $supported serves as a default if no operand matches.
-        * 
-        * @param array $supported The list of supported values to negotiate.
-        * @param array $result Out parameter recording the negotiation results.
-        * @return NULL|string NULL if negotiation fails.
-        *               or string the closest match negotiated, or the default (first entry of $supported).
-        */
-       function negotiate(array $supported, array &$result = NULL) {}
-       /**
-        * Parse HTTP headers.
-        * See also http\Header\Parser.
-        * 
-        * @param string $header The complete string of headers.
-        * @param string $header_class A class extending http\Header.
-        * @return array|false array of parsed headers, where the elements are instances of $header_class if specified.
-        *               or false if parsing fails.
-        */
-       function parse(string $header, string $header_class = NULL) {}
-       /**
-        * Implements Serializable.
-        * 
-        * @return string serialized representation of HTTP header (i.e. "Name: value")
-        */
-       function serialize() {}
-       /**
-        * Convenience method. Alias of http\Header::serialize().
-        * 
-        * @return string the serialized form of the HTTP header (i.e. "Name: value").
-        */
-       function toString() {}
-       /**
-        * Implements Serializable.
-        * 
-        * @param string $serialized The serialized HTTP header (i.e. "Name: value")
-        */
-       function unserialize($serialized) {}
-}
-/**
- * The message class builds the foundation for any request and response message.
- * 
- * See http\Client\Request and http\Client\Response, as well as http\Env\Request and http\Env\Response.
- */
-class Message implements \Countable, \Serializable, \Iterator {
-       /**
-        * No specific type of message.
-        */
-       const TYPE_NONE = 0;
-       /**
-        * A request message.
-        */
-       const TYPE_REQUEST = 1;
-       /**
-        * A response message.
-        */
-       const TYPE_RESPONSE = 2;
-       /**
-        * The message type. See http\Message::TYPE_* constants.
-        * 
-        * @protected
-        * @var int
-        */
-       protected $type = \http\Message::TYPE_NONE;
-       /**
-        * The message's body.
-        * 
-        * @protected
-        * @var \http\Message\Body
-        */
-       protected $body = NULL;
-       /**
-        * The request method if the message is of type request.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $requestMethod = "";
-       /**
-        * The request url if the message is of type request.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $requestUrl = "";
-       /**
-        * The response status phrase if the message is of type response.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $responseStatus = "";
-       /**
-        * The response code if the message is of type response.
-        * 
-        * @protected
-        * @var int
-        */
-       protected $responseCode = 0;
-       /**
-        * A custom HTTP protocol version.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $httpVersion = NULL;
-       /**
-        * Any message headers.
-        * 
-        * @protected
-        * @var array
-        */
-       protected $headers = NULL;
-       /**
-        * Any parent message.
-        * 
-        * @protected
-        * @var \http\Message
-        */
-       protected $parentMessage;
-       /**
-        * Create a new HTTP message.
-        * 
-        * @param mixed $message Either a resource or a string, representing the HTTP message.
-        * @param bool $greedy Whether to read from a $message resource until EOF.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMessageException
-        */
-       function __construct($message = NULL, bool $greedy = true) {}
-       /**
-        * Retrieve the message serialized to a string.
-        * Alias of http\Message::toString().
-        * 
-        * @return string the single serialized HTTP message.
-        */
-       function __toString() {}
-       /**
-        * Append the data of $body to the message's body.
-        * See http\Message::setBody() and http\Message\Body::append().
-        * 
-        * @param \http\Message\Body $body The message body to add.
-        * @return \http\Message self.
-        */
-       function addBody(\http\Message\Body $body) {}
-       /**
-        * Add an header, appending to already existing headers.
-        * See http\Message::addHeaders() and http\Message::setHeader().
-        * 
-        * @param string $name The header name.
-        * @param mixed $value The header value.
-        * @return \http\Message self.
-        */
-       function addHeader(string $name, $value) {}
-       /**
-        * Add headers, optionally appending values, if header keys already exist.
-        * See http\Message::addHeader() and http\Message::setHeaders().
-        * 
-        * @param array $headers The HTTP headers to add.
-        * @param bool $append Whether to append values for existing headers.
-        * @return \http\Message self.
-        */
-       function addHeaders(array $headers, bool $append = false) {}
-       /**
-        * Implements Countable.
-        * 
-        * @return int the count of messages in the chain above the current message.
-        */
-       function count() {}
-       /**
-        * Implements iterator.
-        * See http\Message::valid() and http\Message::rewind().
-        * 
-        * @return \http\Message the current message in the iterated message chain.
-        */
-       function current() {}
-       /**
-        * Detach a clone of this message from any message chain.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Message clone.
-        */
-       function detach() {}
-       /**
-        * Retrieve the message's body.
-        * See http\Message::setBody().
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Message\Body the message body.
-        */
-       function getBody() {}
-       /**
-        * Retrieve a single header, optionally hydrated into a http\Header extending class.
-        * 
-        * @param string $header The header's name.
-        * @param string $into_class The name of a class extending http\Header.
-        * @return mixed|\http\Header mixed the header value if $into_class is NULL.
-        *               or \http\Header descendant.
-        */
-       function getHeader(string $header, string $into_class = NULL) {}
-       /**
-        * Retrieve all message headers.
-        * See http\Message::setHeaders() and http\Message::getHeader().
-        * 
-        * @return array the message's headers.
-        */
-       function getHeaders() {}
-       /**
-        * Retrieve the HTTP protocol version of the message.
-        * See http\Message::setHttpVersion().
-        * 
-        * @return string the HTTP protocol version, e.g. "1.0"; defaults to "1.1".
-        */
-       function getHttpVersion() {}
-       /**
-        * Retrieve the first line of a request or response message.
-        * See http\Message::setInfo and also:
-        * 
-        * * http\Message::getType()
-        * * http\Message::getHttpVersion()
-        * * http\Message::getResponseCode()
-        * * http\Message::getResponseStatus()
-        * * http\Message::getRequestMethod()
-        * * http\Message::getRequestUrl()
-        * 
-        * @return string|NULL string the HTTP message information.
-        *               or NULL if the message is neither of type request nor response.
-        */
-       function getInfo() {}
-       /**
-        * Retrieve any parent message.
-        * See http\Message::reverse().
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @return \http\Message the parent message.
-        */
-       function getParentMessage() {}
-       /**
-        * Retrieve the request method of the message.
-        * See http\Message::setRequestMethod() and http\Message::getRequestUrl().
-        * 
-        * @return string|false string the request method.
-        *               or false if the message was not of type request.
-        */
-       function getRequestMethod() {}
-       /**
-        * Retrieve the request URL of the message.
-        * See http\Message::setRequestUrl().
-        * 
-        * @return string|false string the request URL; usually the path and the querystring.
-        *               or false if the message was not of type request.
-        */
-       function getRequestUrl() {}
-       /**
-        * Retrieve the response code of the message.
-        * See http\Message::setResponseCode() and http\Message::getResponseStatus().
-        * 
-        * @return int|false int the response status code.
-        *               or false if the message is not of type response.
-        */
-       function getResponseCode() {}
-       /**
-        * Retrieve the response status of the message.
-        * See http\Message::setResponseStatus() and http\Message::getResponseCode().
-        * 
-        * @return string|false string the response status phrase.
-        *               or false if the message is not of type response.
-        */
-       function getResponseStatus() {}
-       /**
-        * Retrieve the type of the message.
-        * See http\Message::setType() and http\Message::getInfo().
-        * 
-        * @return int the message type. See http\Message::TYPE_* constants.
-        */
-       function getType() {}
-       /**
-        * Check whether this message is a multipart message based on it's content type.
-        * If the message is a multipart message and a reference $boundary is given, the boundary string of the multipart message will be stored in $boundary.
-        * 
-        * See http\Message::splitMultipartBody().
-        * 
-        * @param string $boundary A reference where the boundary string will be stored.
-        * @return bool whether this is a message with a multipart "Content-Type".
-        */
-       function isMultipart(string &$boundary = NULL) {}
-       /**
-        * Implements Iterator.
-        * See http\Message::current() and http\Message::rewind().
-        * 
-        * @return int a non-sequential integer key.
-        */
-       function key() {}
-       /**
-        * Implements Iterator.
-        * See http\Message::valid() and http\Message::rewind().
-        */
-       function next() {}
-       /**
-        * Prepend message(s) $message to this message, or the top most message of this message chain.
-        * 
-        * > ***NOTE:***
-        * > The message chains must not overlap.
-        * 
-        * @param \http\Message $message The message (chain) to prepend as parent messages.
-        * @param bool $top Whether to prepend to the top-most parent message.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Message self.
-        */
-       function prepend(\http\Message $message, bool $top = true) {}
-       /**
-        * Reverse the message chain and return the former top-most message.
-        * 
-        * > ***NOTE:***
-        * > Message chains are ordered in reverse-parsed order by default, i.e. the last parsed message is the message you'll receive from any call parsing HTTP messages.
-        * >
-        * > This call re-orders the messages of the chain and returns the message that was parsed first with any later parsed messages re-parentized.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Message the other end of the message chain.
-        */
-       function reverse() {}
-       /**
-        * Implements Iterator.
-        */
-       function rewind() {}
-       /**
-        * Implements Serializable.
-        * 
-        * @return string the serialized HTTP message.
-        */
-       function serialize() {}
-       /**
-        * Set the message's body.
-        * See http\Message::getBody() and http\Message::addBody().
-        * 
-        * @param \http\Message\Body $body The new message body.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Message self.
-        */
-       function setBody(\http\Message\Body $body) {}
-       /**
-        * Set a single header.
-        * See http\Message::getHeader() and http\Message::addHeader().
-        * 
-        * > ***NOTE:***
-        * > Prior to v2.5.6/v3.1.0 headers with the same name were merged into a single
-        * > header with values concatenated by comma.
-        * 
-        * @param string $header The header's name.
-        * @param mixed $value The header's value. Removes the header if NULL.
-        * @return \http\Message self.
-        */
-       function setHeader(string $header, $value = NULL) {}
-       /**
-        * Set the message headers.
-        * See http\Message::getHeaders() and http\Message::addHeaders().
-        * 
-        * > ***NOTE:***
-        * > Prior to v2.5.6/v3.1.0 headers with the same name were merged into a single
-        * > header with values concatenated by comma.
-        * 
-        * @param array $headers The message's headers.
-        * @return \http\Message null.
-        */
-       function setHeaders(array $headers = NULL) {}
-       /**
-        * Set the HTTP protocol version of the message.
-        * See http\Message::getHttpVersion().
-        * 
-        * @param string $http_version The protocol version, e.g. "1.1", optionally prefixed by "HTTP/".
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadHeaderException
-        * @return \http\Message self.
-        */
-       function setHttpVersion(string $http_version) {}
-       /**
-        * Set the complete message info, i.e. type and response resp. request information, at once.
-        * See http\Message::getInfo().
-        * 
-        * @param string $http_info The message info (first line of an HTTP message).
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadHeaderException
-        * @return \http\Message self.
-        */
-       function setInfo(string $http_info) {}
-       /**
-        * Set the request method of the message.
-        * See http\Message::getRequestMethod() and http\Message::setRequestUrl().
-        * 
-        * @param string $method The request method.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @return \http\Message self.
-        */
-       function setRequestMethod(string $method) {}
-       /**
-        * Set the request URL of the message.
-        * See http\Message::getRequestUrl() and http\Message::setRequestMethod().
-        * 
-        * @param string $url The request URL.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @return \http\Message self.
-        */
-       function setRequestUrl(string $url) {}
-       /**
-        * Set the response status code.
-        * See http\Message::getResponseCode() and http\Message::setResponseStatus().
-        * 
-        * > ***NOTE:***
-        * > This method also resets the response status phrase to the default for that code.
-        * 
-        * @param int $response_code The response code.
-        * @param bool $strict Whether to check that the response code is between 100 and 599 inclusive.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @return \http\Message self.
-        */
-       function setResponseCode(int $response_code, bool $strict = true) {}
-       /**
-        * Set the response status phrase.
-        * See http\Message::getResponseStatus() and http\Message::setResponseCode().
-        * 
-        * @param string $response_status The status phrase.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @return \http\Message self.
-        */
-       function setResponseStatus(string $response_status) {}
-       /**
-        * Set the message type and reset the message info.
-        * See http\Message::getType() and http\Message::setInfo().
-        * 
-        * @param int $type The desired message type. See the http\Message::TYPE_* constants.
-        * @return \http\Message self.
-        */
-       function setType(int $type) {}
-       /**
-        * Splits the body of a multipart message.
-        * See http\Message::isMultipart() and http\Message\Body::addPart().
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @throws \http\Exception\BadMessageException
-        * @return \http\Message a message chain of all messages of the multipart body.
-        */
-       function splitMultipartBody() {}
-       /**
-        * Stream the message through a callback.
-        * 
-        * @param callable $callback The callback of the form function(http\Message $from, string $data).
-        * @return \http\Message self.
-        */
-       function toCallback(callable $callback) {}
-       /**
-        * Stream the message into stream $stream, starting from $offset, streaming $maxlen at most.
-        * 
-        * @param resource $stream The resource to write to.
-        * @return \http\Message self.
-        */
-       function toStream($stream) {}
-       /**
-        * Retrieve the message serialized to a string.
-        * 
-        * @param bool $include_parent Whether to include all parent messages.
-        * @return string the HTTP message chain serialized to a string.
-        */
-       function toString(bool $include_parent = false) {}
-       /**
-        * Implements Serializable.
-        * 
-        * @param string $data The serialized message.
-        */
-       function unserialize($data) {}
-       /**
-        * Implements Iterator.
-        * See http\Message::current() and http\Message::rewind().
-        * 
-        * @return bool whether http\Message::current() would not return NULL.
-        */
-       function valid() {}
-}
-/**
- * Parse, interpret and compose HTTP (header) parameters.
- */
-class Params implements \ArrayAccess {
-       /**
-        * The default parameter separator (",").
-        */
-       const DEF_PARAM_SEP = ',';
-       /**
-        * The default argument separator (";").
-        */
-       const DEF_ARG_SEP = ';';
-       /**
-        * The default value separator ("=").
-        */
-       const DEF_VAL_SEP = '=';
-       /**
-        * Empty param separator to parse cookies.
-        */
-       const COOKIE_PARAM_SEP = '';
-       /**
-        * Do not interpret the parsed parameters.
-        */
-       const PARSE_RAW = 0;
-       /**
-        * Interpret input as default formatted parameters.
-        */
-       const PARSE_DEFAULT = 17;
-       /**
-        * Parse backslash escaped (quoted) strings.
-        */
-       const PARSE_ESCAPED = 1;
-       /**
-        * Urldecode single units of parameters, arguments and values.
-        */
-       const PARSE_URLENCODED = 4;
-       /**
-        * Parse sub dimensions indicated by square brackets.
-        */
-       const PARSE_DIMENSION = 8;
-       /**
-        * Parse URL querystring (same as http\Params::PARSE_URLENCODED|http\Params::PARSE_DIMENSION).
-        */
-       const PARSE_QUERY = 12;
-       /**
-        * Parse [RFC5987](http://tools.ietf.org/html/rfc5987) style encoded character set and language information embedded in HTTP header params.
-        */
-       const PARSE_RFC5987 = 16;
-       /**
-        * Parse [RFC5988](http://tools.ietf.org/html/rfc5988) (Web Linking) tags of Link headers.
-        */
-       const PARSE_RFC5988 = 32;
-       /**
-        * The (parsed) parameters.
-        * 
-        * @public
-        * @var array
-        */
-       public $params = NULL;
-       /**
-        * The parameter separator(s).
-        * 
-        * @public
-        * @var array
-        */
-       public $param_sep = \http\Params::DEF_PARAM_SEP;
-       /**
-        * The argument separator(s).
-        * 
-        * @public
-        * @var array
-        */
-       public $arg_sep = \http\Params::DEF_ARG_SEP;
-       /**
-        * The value separator(s).
-        * 
-        * @public
-        * @var array
-        */
-       public $val_sep = \http\Params::DEF_VAL_SEP;
-       /**
-        * The modus operandi of the parser. See http\Params::PARSE_* constants.
-        * 
-        * @public
-        * @var int
-        */
-       public $flags = \http\Params::PARSE_DEFAULT;
-       /**
-        * Instantiate a new HTTP (header) parameter set.
-        * 
-        * @param mixed $params Pre-parsed parameters or a string to be parsed.
-        * @param mixed $ps The parameter separator(s).
-        * @param mixed $as The argument separator(s).
-        * @param mixed $vs The value separator(s).
-        * @param int $flags The modus operandi. See http\Params::PARSE_* constants.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        */
-       function __construct($params = NULL, $ps = NULL, $as = NULL, $vs = NULL, int $flags = NULL) {}
-       /**
-        * String cast handler. Alias of http\Params::toString().
-        * Returns a stringified version of the parameters.
-        * 
-        * @return string version of the parameters.
-        */
-       function __toString() {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param string $name The offset to look after.
-        * @return bool Existence.
-        */
-       function offsetExists($name) {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param string $name The offset to retrieve.
-        * @return mixed contents at offset.
-        */
-       function offsetGet($name) {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param string $name The offset to modify.
-        * @param mixed $value The value to set.
-        */
-       function offsetSet($name, $value) {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param string $name The offset to delete.
-        */
-       function offsetUnset($name) {}
-       /**
-        * Convenience method that simply returns http\Params::$params.
-        * 
-        * @return array of parameters.
-        */
-       function toArray() {}
-       /**
-        * Returns a stringified version of the parameters.
-        * 
-        * @return string version of the parameters.
-        */
-       function toString() {}
-}
-/**
- * The http\QueryString class provides versatile facilities to retrieve, use and manipulate query strings and form data.
- */
-class QueryString implements \Serializable, \ArrayAccess, \IteratorAggregate {
-       /**
-        * Cast requested value to bool.
-        */
-       const TYPE_BOOL = 17;
-       /**
-        * Cast requested value to int.
-        */
-       const TYPE_INT = 4;
-       /**
-        * Cast requested value to float.
-        */
-       const TYPE_FLOAT = 5;
-       /**
-        * Cast requested value to string.
-        */
-       const TYPE_STRING = 6;
-       /**
-        * Cast requested value to an array.
-        */
-       const TYPE_ARRAY = 7;
-       /**
-        * Cast requested value to an object.
-        */
-       const TYPE_OBJECT = 8;
-       /**
-        * The global instance. See http\QueryString::getGlobalInstance().
-        * 
-        * @private
-        * @var \http\QueryString
-        */
-       private $instance = NULL;
-       /**
-        * The data.
-        * 
-        * @private
-        * @var array
-        */
-       private $queryArray = NULL;
-       /**
-        * Create an independent querystring instance.
-        * 
-        * @param mixed $params The query parameters to use or parse.
-        * @throws \http\Exception\BadQueryStringException
-        */
-       function __construct($params = NULL) {}
-       /**
-        * Get the string representation of the querystring (x-www-form-urlencoded).
-        * 
-        * @return string the x-www-form-urlencoded querystring.
-        */
-       function __toString() {}
-       /**
-        * Retrieve an querystring value.
-        * 
-        * See http\QueryString::TYPE_* constants.
-        * 
-        * @param string $name The key to retrieve the value for.
-        * @param mixed $type The type to cast the value to. See http\QueryString::TYPE_* constants.
-        * @param mixed $defval The default value to return if the key $name does not exist.
-        * @param bool $delete Whether to delete the entry from the querystring after retrieval.
-        * @return \http\QueryString|string|mixed|mixed|string \http\QueryString if called without arguments.
-        *               or string the whole querystring if $name is of zero length.
-        *               or mixed $defval if the key $name does not exist.
-        *               or mixed the querystring value cast to $type if $type was specified and the key $name exists.
-        *               or string the querystring value if the key $name exists and $type is not specified or equals http\QueryString::TYPE_STRING.
-        */
-       function get(string $name = NULL, $type = NULL, $defval = NULL, bool $delete = false) {}
-       /**
-        * Retrieve an array value with at offset $name.
-        * 
-        * @param string $name The key to look up.
-        * @param mixed $defval The default value to return if the offset $name does not exist.
-        * @param bool $delete Whether to remove the key and value from the querystring after retrieval.
-        * @return array|mixed array the (casted) value.
-        *               or mixed $defval if offset $name does not exist.
-        */
-       function getArray(string $name, $defval = NULL, bool $delete = false) {}
-       /**
-        * Retrieve a boolean value at offset $name.
-        * 
-        * @param string $name The key to look up.
-        * @param mixed $defval The default value to return if the offset $name does not exist.
-        * @param bool $delete Whether to remove the key and value from the querystring after retrieval.
-        * @return bool|mixed bool the (casted) value.
-        *               or mixed $defval if offset $name does not exist.
-        */
-       function getBool(string $name, $defval = NULL, bool $delete = false) {}
-       /**
-        * Retrieve a float value at offset $name.
-        * 
-        * @param string $name The key to look up.
-        * @param mixed $defval The default value to return if the offset $name does not exist.
-        * @param bool $delete Whether to remove the key and value from the querystring after retrieval.
-        * @return float|mixed float the (casted) value.
-        *               or mixed $defval if offset $name does not exist.
-        */
-       function getFloat(string $name, $defval = NULL, bool $delete = false) {}
-       /**
-        * Retrieve the global querystring instance referencing $_GET.
-        * 
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\QueryString the http\QueryString::$instance
-        */
-       function getGlobalInstance() {}
-       /**
-        * Retrieve a int value at offset $name.
-        * 
-        * @param string $name The key to look up.
-        * @param mixed $defval The default value to return if the offset $name does not exist.
-        * @param bool $delete Whether to remove the key and value from the querystring after retrieval.
-        * @return int|mixed int the (casted) value.
-        *               or mixed $defval if offset $name does not exist.
-        */
-       function getInt(string $name, $defval = NULL, bool $delete = false) {}
-       /**
-        * Implements IteratorAggregate.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \InvalidArgumentException
-        */
-       function getIterator() {}
-       /**
-        * Retrieve a object value with at offset $name.
-        * 
-        * @param string $name The key to look up.
-        * @param mixed $defval The default value to return if the offset $name does not exist.
-        * @param bool $delete Whether to remove the key and value from the querystring after retrieval.
-        * @return object|mixed object the (casted) value.
-        *               or mixed $defval if offset $name does not exist.
-        */
-       function getObject(string $name, $defval = NULL, bool $delete = false) {}
-       /**
-        * Retrieve a string value with at offset $name.
-        * 
-        * @param string $name The key to look up.
-        * @param mixed $defval The default value to return if the offset $name does not exist.
-        * @param bool $delete Whether to remove the key and value from the querystring after retrieval.
-        * @return string|mixed string the (casted) value.
-        *               or mixed $defval if offset $name does not exist.
-        */
-       function getString(string $name, $defval = NULL, bool $delete = false) {}
-       /**
-        * Set additional $params to a clone of this instance.
-        * See http\QueryString::set().
-        * 
-        * > ***NOTE:***
-        * > This method returns a clone (copy) of this instance.
-        * 
-        * @param mixed $params Additional params as object, array or string to parse.
-        * @throws \http\Exception\BadQueryStringException
-        * @return \http\QueryString clone.
-        */
-       function mod($params = NULL) {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param string $name The offset to look up.
-        * @return bool whether the key $name isset.
-        */
-       function offsetExists($name) {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param mixed $offset The offset to look up.
-        * @return mixed|NULL mixed the value locate at offset $name.
-        *               or NULL if key $name could not be found.
-        */
-       function offsetGet($offset) {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param string $name The key to set the value for.
-        * @param mixed $data The data to place at offset $name.
-        */
-       function offsetSet($name, $data) {}
-       /**
-        * Implements ArrayAccess.
-        * 
-        * @param string $name The offset to look up.
-        */
-       function offsetUnset($name) {}
-       /**
-        * Implements Serializable.
-        * See http\QueryString::toString().
-        * 
-        * @return string the x-www-form-urlencoded querystring.
-        */
-       function serialize() {}
-       /**
-        * Set additional querystring entries.
-        * 
-        * @param mixed $params Additional params as object, array or string to parse.
-        * @return \http\QueryString self.
-        */
-       function set($params) {}
-       /**
-        * Simply returns http\QueryString::$queryArray.
-        * 
-        * @return array the $queryArray property.
-        */
-       function toArray() {}
-       /**
-        * Get the string representation of the querystring (x-www-form-urlencoded).
-        * 
-        * @return string the x-www-form-urlencoded querystring.
-        */
-       function toString() {}
-       /**
-        * Implements Serializable.
-        * 
-        * @param string $serialized The x-www-form-urlencoded querystring.
-        * @throws \http\Exception
-        */
-       function unserialize($serialized) {}
-       /**
-        * Translate character encodings of the querystring with ext/iconv.
-        * 
-        * > ***NOTE:***
-        * > This method is only available when ext/iconv support was enabled at build time.
-        * 
-        * @param string $from_enc The encoding to convert from.
-        * @param string $to_enc The encoding to convert to.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadConversionException
-        * @return \http\QueryString self.
-        */
-       function xlate(string $from_enc, string $to_enc) {}
-}
-/**
- * The http\Url class provides versatile means to parse, construct and manipulate URLs.
- */
-class Url  {
-       /**
-        * Replace parts of the old URL with parts of the new.
-        */
-       const REPLACE = 0;
-       /**
-        * Whether a relative path should be joined into the old path.
-        */
-       const JOIN_PATH = 1;
-       /**
-        * Whether the querystrings should be joined.
-        */
-       const JOIN_QUERY = 2;
-       /**
-        * Strip the user information from the URL.
-        */
-       const STRIP_USER = 4;
-       /**
-        * Strip the password from the URL.
-        */
-       const STRIP_PASS = 8;
-       /**
-        * Strip user and password information from URL (same as STRIP_USER|STRIP_PASS).
-        */
-       const STRIP_AUTH = 12;
-       /**
-        * Do not include the port.
-        */
-       const STRIP_PORT = 32;
-       /**
-        * Do not include the URL path.
-        */
-       const STRIP_PATH = 64;
-       /**
-        * Do not include the URL querystring.
-        */
-       const STRIP_QUERY = 128;
-       /**
-        * Strip the fragment (hash) from the URL.
-        */
-       const STRIP_FRAGMENT = 256;
-       /**
-        * Strip everything except scheme and host information.
-        */
-       const STRIP_ALL = 492;
-       /**
-        * Import initial URL parts from the SAPI environment.
-        */
-       const FROM_ENV = 4096;
-       /**
-        * Whether to sanitize the URL path (consolidate double slashes, directory jumps etc.)
-        */
-       const SANITIZE_PATH = 8192;
-       /**
-        * Parse UTF-8 encoded multibyte sequences.
-        */
-       const PARSE_MBUTF8 = 131072;
-       /**
-        * Parse locale encoded multibyte sequences (on systems with wide character support).
-        */
-       const PARSE_MBLOC = 65536;
-       /**
-        * Parse and convert multibyte hostnames according to IDNA (with IDNA support).
-        */
-       const PARSE_TOIDN = 1048576;
-       /**
-        * Explicitly request IDNA2003 implementation if available (libidn, idnkit or ICU).
-        */
-       const PARSE_TOIDN_2003 = 9437184;
-       /**
-        * Explicitly request IDNA2008 implementation if available (libidn2, idnkit2 or ICU).
-        */
-       const PARSE_TOIDN_2008 = 5242880;
-       /**
-        * Percent encode multibyte sequences in the userinfo, path, query and fragment parts of the URL.
-        */
-       const PARSE_TOPCT = 2097152;
-       /**
-        * Continue parsing when encountering errors.
-        */
-       const IGNORE_ERRORS = 268435456;
-       /**
-        * Suppress errors/exceptions.
-        */
-       const SILENT_ERRORS = 536870912;
-       /**
-        * Standard flags used by default internally for e.g. http\Message::setRequestUrl().
-        *   Enables joining path and query, sanitizing path, multibyte/unicode, international domain names and transient percent encoding.
-        */
-       const STDFLAGS = 3350531;
-       /**
-        * The URL's scheme.
-        * 
-        * @public
-        * @var string
-        */
-       public $scheme = NULL;
-       /**
-        * Authenticating user.
-        * 
-        * @public
-        * @var string
-        */
-       public $user = NULL;
-       /**
-        * Authentication password.
-        * 
-        * @public
-        * @var string
-        */
-       public $pass = NULL;
-       /**
-        * Hostname/domain.
-        * 
-        * @public
-        * @var string
-        */
-       public $host = NULL;
-       /**
-        * Port.
-        * 
-        * @public
-        * @var string
-        */
-       public $port = NULL;
-       /**
-        * URL path.
-        * 
-        * @public
-        * @var string
-        */
-       public $path = NULL;
-       /**
-        * URL querystring.
-        * 
-        * @public
-        * @var string
-        */
-       public $query = NULL;
-       /**
-        * URL fragment (hash).
-        * 
-        * @public
-        * @var string
-        */
-       public $fragment = NULL;
-       /**
-        * Create an instance of an http\Url.
-        * 
-        * > ***NOTE:***
-        * > Prior to v3.0.0, the default for the $flags parameter was http\Url::FROM_ENV.
-        * 
-        * See also http\Env\Url.
-        * 
-        * @param mixed $old_url Initial URL parts. Either an array, object, http\Url instance or string to parse.
-        * @param mixed $new_url Overriding URL parts. Either an array, object, http\Url instance or string to parse.
-        * @param int $flags The modus operandi of constructing the url. See http\Url constants.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadUrlException
-        */
-       function __construct($old_url = NULL, $new_url = NULL, int $flags = 0) {}
-       /**
-        * String cast handler. Alias of http\Url::toString().
-        * 
-        * @return string the URL as string.
-        */
-       function __toString() {}
-       /**
-        * Clone this URL and apply $parts to the cloned URL.
-        * 
-        * > ***NOTE:***
-        * > This method returns a clone (copy) of this instance.
-        * 
-        * @param mixed $parts New URL parts.
-        * @param int $flags Modus operandi of URL construction. See http\Url constants.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadUrlException
-        * @return \http\Url clone.
-        */
-       function mod($parts, int $flags = \http\Url::JOIN_PATH|http\Url::JOIN_QUERY|http\Url::SANITIZE_PATH) {}
-       /**
-        * Retrieve the URL parts as array.
-        * 
-        * @return array the URL parts.
-        */
-       function toArray() {}
-       /**
-        * Get the string prepresentation of the URL.
-        * 
-        * @return string the URL as string.
-        */
-       function toString() {}
-}
-/**
- * The http\Client\Curl namespace holds option value constants specific to the curl driver of the http\Client.
- * 
- * Head down for the [list of available request options](http/Client/Curl#Options:) as well as the
- * [list of available client configuration options](http/Client/Curl#Configuration:).
- */
-namespace http\Client\Curl;
-/**
- * Bitmask of available libcurl features.
- *   See http\Client\Curl\Features namespace.
- */
-const FEATURES = 12568477;
-/**
- * List of library versions of or linked into libcurl,
- *   e.g. "libcurl/7.50.0 OpenSSL/1.0.2h zlib/1.2.8 libidn/1.32 nghttp2/1.12.0".
- *   See http\Client\Curl\Versions namespace.
- */
-const VERSIONS = 'libcurl/7.68.0 OpenSSL/1.1.1f zlib/1.2.11 brotli/1.0.7 libidn2/2.2.0 libpsl/0.21.0 (+libidn2/2.2.0) libssh/0.9.3/openssl/zlib nghttp2/1.40.0 librtmp/2.3';
-/**
- * Use HTTP/1.0 protocol version.
- */
-const HTTP_VERSION_1_0 = 1;
-/**
- * Use HTTP/1.1 protocol version.
- */
-const HTTP_VERSION_1_1 = 2;
-/**
- * Attempt to use HTTP/2 protocol version. Available if libcurl is v7.33.0 or more recent and was built with nghttp2 support.
- */
-const HTTP_VERSION_2_0 = 3;
-/**
- * Attempt to use version 2 for HTTPS, version 1.1 for HTTP. Available if libcurl is v7.47.0 or more recent and was built with http2 support.
- */
-const HTTP_VERSION_2TLS = 4;
-/**
- * Declare prior knowledge that the server supports plain (non-TLS) HTTP/2. Available if libcurl is v7.49.0 or more recent and was built with http2 support.
- */
-const HTTP_VERSION_2_PRIOR_KNOWLEDGE = 5;
-/**
- * Force usage of HTTP/3. See also http\Client\Curl::$altsvc. Available if libcurl is v7.66.0 or more recent.
- */
-const HTTP_VERSION_3 = 30;
-/**
- * Use any HTTP protocol version.
- */
-const HTTP_VERSION_ANY = 0;
-/**
- * Use TLS v1.0 encryption. Available if libcurl is v7.34.0 or more recent.
- */
-const SSL_VERSION_TLSv1_0 = 4;
-/**
- * Use TLS v1.1 encryption. Available if libcurl is v7.34.0 or more recent.
- */
-const SSL_VERSION_TLSv1_1 = 5;
-/**
- * Use TLS v1.2 encryption. Available if libcurl is v7.34.0 or more recent.
- */
-const SSL_VERSION_TLSv1_2 = 6;
-/**
- * Use TLS v1.3 encryption. Available if libcurl is v7.52.0 or more recent.
- */
-const SSL_VERSION_TLSv1_3 = 7;
-/**
- * Use any TLS v1 encryption.
- */
-const SSL_VERSION_TLSv1 = 1;
-/**
- * Use SSL v2 encryption.
- */
-const SSL_VERSION_SSLv2 = 2;
-/**
- * Use SSL v3 encryption.
- */
-const SSL_VERSION_SSLv3 = 3;
-/**
- * Use any encryption.
- */
-const SSL_VERSION_ANY = 0;
-/**
- * Use max default encryption. To be bitwise ORed to a http\Client\Curl\SSL_VERSION_ constant. Available if libcurl is v7.54.0 or more recent.
- */
-const SSL_VERSION_MAX_DEFAULT = 65536;
-/**
- * Use upt to TLS v1.0 encryption. To be bitwise ORed to a http\Client\Curl\SSL_VERSION_ constant. Available if libcurl is v7.54.0 or more recent.
- */
-const SSL_VERSION_MAX_TLSv1_0 = 262144;
-/**
- * Use up to TLS v1.1 encryption. To be bitwise ORed to a http\Client\Curl\SSL_VERSION_ constant. Available if libcurl is v7.54.0 or more recent.
- */
-const SSL_VERSION_MAX_TLSv1_1 = 327680;
-/**
- * Use up to TLS v1.2 encryption. To be bitwise ORed to a http\Client\Curl\SSL_VERSION_ constant. Available if libcurl is v7.54.0 or more recent.
- */
-const SSL_VERSION_MAX_TLSv1_2 = 393216;
-/**
- * Use up to TLS v1.3 encryption. To be bitwise ORed to a http\Client\Curl\SSL_VERSION_ constant. Available if libcurl is v7.54.0 or more recent.
- */
-const SSL_VERSION_MAX_TLSv1_3 = 458752;
-/**
- * Use TLS SRP authentication. Available if libcurl is v7.21.4 or more recent and was built with gnutls or openssl with TLS-SRP support.
- */
-const TLSAUTH_SRP = 1;
-/**
- * Use IPv4 resolver.
- */
-const IPRESOLVE_V4 = 1;
-/**
- * Use IPv6 resolver.
- */
-const IPRESOLVE_V6 = 2;
-/**
- * Use any resolver.
- */
-const IPRESOLVE_ANY = 0;
-/**
- * Don't use authentication.
- */
-const AUTH_NONE = 0;
-/**
- * Use Basic authentication.
- */
-const AUTH_BASIC = 1;
-/**
- * Use Digest authentication.
- */
-const AUTH_DIGEST = 2;
-/**
- * Use IE (lower v7) quirks with Digest authentication. Available if libcurl is v7.19.3 or more recent.
- */
-const AUTH_DIGEST_IE = 16;
-/**
- * Use NTLM authentication.
- */
-const AUTH_NTLM = 8;
-/**
- * Use GSS-Negotiate authentication.
- */
-const AUTH_GSSNEG = 4;
-/**
- * Use HTTP Netgotiate authentication (SPNEGO, RFC4559). Available if libcurl is v7.38.0 or more recent.
- */
-const AUTH_SPNEGO = 4;
-/**
- * Bearer authentication. Set bearer with http\Client\Curl::$xoauth2_bearer request option. Available if libcurl is v7.61.0 or more recent.
- */
-const AUTH_BEARER = 64;
-/**
- * Use AWS SIGv4 authentication. Available if libcurl is v7.75.0 or more recent.
- */
-const AUTH_AWS_SIGV4 = NULL;
-/**
- * Use any authentication.
- */
-const AUTH_ANY = -17;
-/**
- * Use SOCKSv4 proxy protocol.
- */
-const PROXY_SOCKS4 = 4;
-/**
- * Use SOCKSv4a proxy protocol.
- */
-const PROXY_SOCKS4A = 6;
-/**
- * Use SOCKS5h proxy protocol.
- */
-const PROXY_SOCKS5_HOSTNAME = 7;
-/**
- * Use SOCKS5 proxy protoccol.
- */
-const PROXY_SOCKS5 = 5;
-/**
- * Use HTTP/1.1 proxy protocol.
- */
-const PROXY_HTTP = 0;
-/**
- * Use HTTP/1.0 proxy protocol. Available if libcurl is v7.19.4 or more recent.
- */
-const PROXY_HTTP_1_0 = 1;
-/**
- * Keep POSTing on 301 redirects. Available if libcurl is v7.19.1 or more recent.
- */
-const POSTREDIR_301 = 1;
-/**
- * Keep POSTing on 302 redirects. Available if libcurl is v7.19.1 or more recent.
- */
-const POSTREDIR_302 = 2;
-/**
- * Keep POSTing on 303 redirects. Available if libcurl is v7.19.1 or more recent.
- */
-const POSTREDIR_303 = 4;
-/**
- * Keep POSTing on any redirect. Available if libcurl is v7.19.1 or more recent.
- */
-const POSTREDIR_ALL = 7;
-/**
- * Do only read from but not write to the Alt-Svc cache file. Available if libcurl is v7.64.1 or more recent.
- */
-const ALTSVC_READONLYFILE = 4;
-/**
- * Accept alternative services offered over HTTP/1.1. Available if libcurl is v7.64.1 or more recent.
- */
-const ALTSVC_H1 = 8;
-/**
- * Accept alternative services offered over HTTP/2. Available if libcurl is v7.64.1 or more recent.
- */
-const ALTSVC_H2 = 16;
-/**
- * Accept alternative services offered over HTTP/3. Available if libcurl is v7.64.1 or more recent.
- */
-const ALTSVC_H3 = 32;
-/**
- * Enable the cache. Available if libcurl is v7.74.0 or more recent.
- */
-const HSTS_ENABLE = NULL;
-/**
- * Do only read from but not write to the HSTS cache file. Available if libcurl is v7.74.0 or more recent.
- */
-const HSTS_READONLYFILE = NULL;
-namespace http\Client;
-/**
- * The http\Client\Request class provides an HTTP message implementation tailored to represent a request message to be sent by the client.
- * 
- * See http\Client::enqueue().
- */
-class Request extends \http\Message {
-       /**
-        * Array of options for this request, which override client options.
-        * 
-        * @protected
-        * @var array
-        */
-       protected $options = NULL;
-       /**
-        * Create a new client request message to be enqueued and sent by http\Client.
-        * 
-        * @param string $meth The request method.
-        * @param string $url The request URL.
-        * @param array $headers HTTP headers.
-        * @param \http\Message\Body $body Request body.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        */
-       function __construct(string $meth = NULL, string $url = NULL, array $headers = NULL, \http\Message\Body $body = NULL) {}
-       /**
-        * Add querystring data.
-        * See http\Client\Request::setQuery() and http\Message::setRequestUrl().
-        * 
-        * @param mixed $query_data Additional querystring data.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadQueryStringException
-        * @return \http\Client\Request self.
-        */
-       function addQuery($query_data) {}
-       /**
-        * Add specific SSL options.
-        * See http\Client\Request::setSslOptions(), http\Client\Request::setOptions() and http\Client\Curl\$ssl options.
-        * 
-        * @param array $ssl_options Add this SSL options.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client\Request self.
-        */
-       function addSslOptions(array $ssl_options = NULL) {}
-       /**
-        * Extract the currently set "Content-Type" header.
-        * See http\Client\Request::setContentType().
-        * 
-        * @return string|NULL string the currently set content type.
-        *               or NULL if no "Content-Type" header is set.
-        */
-       function getContentType() {}
-       /**
-        * Get priorly set options.
-        * See http\Client\Request::setOptions().
-        * 
-        * @return array options.
-        */
-       function getOptions() {}
-       /**
-        * Retrieve the currently set querystring.
-        * 
-        * @return string|NULL string the currently set querystring.
-        *               or NULL if no querystring is set.
-        */
-       function getQuery() {}
-       /**
-        * Retrieve priorly set SSL options.
-        * See http\Client\Request::getOptions() and http\Client\Request::setSslOptions().
-        * 
-        * @return array SSL options.
-        */
-       function getSslOptions() {}
-       /**
-        * Set the MIME content type of the request message.
-        * 
-        * @param string $content_type The MIME type used as "Content-Type".
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Client\Request self.
-        */
-       function setContentType(string $content_type) {}
-       /**
-        * Set client options.
-        * See http\Client::setOptions() and http\Client\Curl.
-        * 
-        * Request specific options override general options which were set in the client.
-        * 
-        * > ***NOTE:***
-        * > Only options specified prior enqueueing a request are applied to the request.
-        * 
-        * @param array $options The options to set.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client\Request self.
-        */
-       function setOptions(array $options = NULL) {}
-       /**
-        * (Re)set the querystring.
-        * See http\Client\Request::addQuery() and http\Message::setRequestUrl().
-        * 
-        * @param mixed $query_data
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadQueryStringException
-        * @return \http\Client\Request self.
-        */
-       function setQuery($query_data) {}
-       /**
-        * Specifically set SSL options.
-        * See http\Client\Request::setOptions() and http\Client\Curl\$ssl options.
-        * 
-        * @param array $ssl_options Set SSL options to this array.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Client\Request self.
-        */
-       function setSslOptions(array $ssl_options = NULL) {}
-}
-/**
- * The http\Client\Response class represents an HTTP message the client returns as answer from a server to an http\Client\Request.
- */
-class Response extends \http\Message {
-       /**
-        * Extract response cookies.
-        * Parses any "Set-Cookie" response headers into an http\Cookie list. See http\Cookie::__construct().
-        * 
-        * @param int $flags Cookie parser flags.
-        * @param array $allowed_extras List of keys treated as extras.
-        * @return array list of http\Cookie instances.
-        */
-       function getCookies(int $flags = 0, array $allowed_extras = NULL) {}
-       /**
-        * Retrieve transfer related information after the request has completed.
-        * See http\Client::getTransferInfo().
-        * 
-        * @param string $name A key to retrieve out of the transfer info.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\BadMethodCallException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return object|mixed object stdClass instance with all transfer info if $name was not given.
-        *               or mixed the specific transfer info for $name.
-        */
-       function getTransferInfo(string $name = NULL) {}
-}
-namespace http\Client\Curl;
-/**
- * Interface to an user event loop implementation for http\Client::configure()'s $use_eventloop option.
- * 
- * > ***NOTE:***
- * > This interface was added in v2.6.0, resp. v3.1.0.
- */
-interface User  {
-       /**
-        * No action.
-        */
-       const POLL_NONE = 0;
-       /**
-        * Poll for read readiness.
-        */
-       const POLL_IN = 1;
-       /**
-        * Poll for write readiness.
-        */
-       const POLL_OUT = 2;
-       /**
-        * Poll for read/write readiness.
-        */
-       const POLL_INOUT = 3;
-       /**
-        * Stop polling for activity on this descriptor.
-        */
-       const POLL_REMOVE = 4;
-       /**
-        * Initialize the event loop.
-        * 
-        * @param callable $run as function(http\Client $c, resource $s = null, int $action = http\Client\Curl\User::POLL_NONE) : int
-        *   Internal callback returning the number of unfinished requests pending.
-        * 
-        * 
-        * > ***NOTE***:
-        * > The callback should be run when a timeout occurs or a watched socket needs action.
-        */
-       function init(callable $run);
-       /**
-        * Run the loop as long as it does not block.
-        * 
-        * > ***NOTE:***
-        * > This method is called by http\Client::once(), so it does not need to have an actual implementation if http\Client::once() is never called.
-        */
-       function once();
-       /**
-        * Run the loop.
-        * 
-        * > ***NOTE:***
-        * > This method is called by http\Client::send(), so it does not need to have an actual implementation if http\Client::send() is never called.
-        */
-       function send();
-       /**
-        * Register (or deregister) a socket watcher.
-        * 
-        * @param resource $socket The socket descriptor to watch.
-        * @param int $poll http\Client\Curl\User::POLL_* constant.
-        */
-       function socket($socket, int $poll);
-       /**
-        * Register a timeout watcher.
-        * 
-        * @param int $timeout_ms Desired maximum timeout in milliseconds.
-        */
-       function timer(int $timeout_ms);
-       /**
-        * Wait/poll/select (block the loop) until events fire.
-        * 
-        * > ***NOTE:***
-        * > This method is called by http\Client::wait(), so it does not need to have an actual implementation if http\Client::wait() is never called.
-        * 
-        * @param int $timeout_ms Block for at most this milliseconds.
-        */
-       function wait(int $timeout_ms = null);
-}
-/**
- * CURL feature constants.
- * 
- * > ***NOTE:***
- * > These constants have been added in v2.6.0, resp. v3.1.0.
- */
-namespace http\Client\Curl\Features;
-/**
- * Whether libcurl supports asynchronous domain name resolution.
- */
-const ASYNCHDNS = 128;
-/**
- * Whether libcurl supports the Generic Security Services Application Program Interface. Available if libcurl is v7.38.0 or more recent.
- */
-const GSSAPI = 131072;
-/**
- * Whether libcurl supports HTTP Generic Security Services negotiation.
- */
-const GSSNEGOTIATE = 32;
-/**
- * Whether libcurl supports the HTTP/2 protocol. Available if libcurl is v7.33.0 or more recent.
- */
-const HTTP2 = 65536;
-/**
- * Whether libcurl supports international domain names.
- */
-const IDN = 1024;
-/**
- * Whether libcurl supports IPv6.
- */
-const IPV6 = 1;
-/**
- * Whether libcurl supports the old Kerberos protocol.
- */
-const KERBEROS4 = 2;
-/**
- * Whether libcurl supports the more recent Kerberos v5 protocol. Available if libcurl is v7.40.0 or more recent.
- */
-const KERBEROS5 = 262144;
-/**
- * Whether libcurl supports large files.
- */
-const LARGEFILE = 512;
-/**
- * Whether libcurl supports gzip/deflate compression.
- */
-const LIBZ = 8;
-/**
- * Whether libcurl supports the NT Lan Manager authentication.
- */
-const NTLM = 16;
-/**
- * Whether libcurl supports NTLM delegation to a winbind helper. Available if libcurl is v7.22.0 or more recent.
- */
-const NTLM_WB = 32768;
-/**
- * Whether libcurl supports the Public Suffix List for cookie host handling. Available if libcurl is v7.47.0 or more recent.
- */
-const PSL = 1048576;
-/**
- * Whether libcurl supports the Simple and Protected GSSAPI Negotiation Mechanism.
- */
-const SPNEGO = 256;
-/**
- * Whether libcurl supports SSL/TLS protocols.
- */
-const SSL = 4;
-/**
- * Whether libcurl supports the Security Support Provider Interface.
- */
-const SSPI = 2048;
-/**
- * Whether libcurl supports TLS Secure Remote Password authentication. Available if libcurl is v7.21.4 or more recent.
- */
-const TLSAUTH_SRP = 16384;
-/**
- * Whether libcurl supports connections to unix sockets. Available if libcurl is v7.40.0 or more recent.
- */
-const UNIX_SOCKETS = 524288;
-/**
- * CURL version constants.
- */
-namespace http\Client\Curl\Versions;
-/**
- * Version string of libcurl, e.g. "7.50.0".
- */
-const CURL = '7.68.0';
-/**
- * Version string of the SSL/TLS library, e.g. "OpenSSL/1.0.2h".
- */
-const SSL = 'OpenSSL/1.1.1f';
-/**
- * Version string of the zlib compression library, e.g. "1.2.8".
- */
-const LIBZ = '1.2.11';
-/**
- * Version string of the c-ares library, e.g. "1.11.0".
- */
-const ARES = NULL;
-/**
- * Version string of the IDN library, e.g. "1.32".
- */
-const IDN = '2.2.0';
-/**
- * Version string of the iconv library. Added in v4.1.0.
- */
-const ICONV = NULL;
-/**
- * Version string of the brotli library. Added in v4.1.0. Available if libcurl is v7.57.0 or more recent.
- */
-const BROTLI = '1.0.7';
-/**
- * Version string of nghttp2. Added in v4.1.0. Available if libcurl is v7.66.0 or more recent.
- */
-const NGHTTP2 = '1.40.0';
-/**
- * Version string of quiche/nghttp3. Added in v4.1.0. Available if libcurl is v7.66.0 or more recent.
- */
-const QUIC = NULL;
-/**
- * Default path to the certificate bundle file. Added in v4.1.0. Available if libcurl is v7.70.0 or more recent.
- */
-const CAINFO = NULL;
-/**
- * Default path to the certificate bundle directory. Added in v4.1.0. Available if libcurl is v7.70.0 or more recent.
- */
-const CAPATH = NULL;
-/**
- * Version string of the zstd library. Added in v4.1.0. Available if libcurl is v7.72.0 or more recent.
- */
-const ZSTD = NULL;
-/**
- * Version string of the hyper library. Added in v4.1.0. Available if libcurl is v7.75.0 or more recent.
- */
-const HYPER = NULL;
-namespace http\Encoding;
-/**
- * Base class for encoding stream implementations.
- */
-abstract class Stream  {
-       /**
-        * Do no intermittent flushes.
-        */
-       const FLUSH_NONE = 0;
-       /**
-        * Flush at appropriate transfer points.
-        */
-       const FLUSH_SYNC = 1048576;
-       /**
-        * Flush at each IO operation.
-        */
-       const FLUSH_FULL = 2097152;
-       /**
-        * Base constructor for encoding stream implementations.
-        * 
-        * @param int $flags See http\Encoding\Stream and implementation specific constants.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        */
-       function __construct(int $flags = 0) {}
-       /**
-        * Check whether the encoding stream is already done.
-        * 
-        * @return bool whether the encoding stream is completed.
-        */
-       function done() {}
-       /**
-        * Finish and reset the encoding stream.
-        * Returns any pending data.
-        * 
-        * @return string any pending data.
-        */
-       function finish() {}
-       /**
-        * Flush the encoding stream.
-        * Returns any pending data.
-        * 
-        * @return string any pending data.
-        */
-       function flush() {}
-       /**
-        * Update the encoding stream with more input.
-        * 
-        * @param string $data The data to pass through the stream.
-        * @return string processed data.
-        */
-       function update(string $data) {}
-}
-namespace http\Encoding\Stream;
-/**
- * A [brotli](https://brotli.org) decoding stream.
- * 
- * > ***NOTE:***
- * > This class has been added in v3.2.0.
- */
-class Debrotli extends \http\Encoding\Stream {
-       /**
-        * Decode brotli encoded data.
-        * 
-        * @param string $data The data to uncompress.
-        * @return string the uncompressed data.
-        */
-       function decode(string $data) {}
-}
-/**
- * A stream decoding data encoded with chunked transfer encoding.
- */
-class Dechunk extends \http\Encoding\Stream {
-       /**
-        * Decode chunked encoded data.
-        * 
-        * @param string $data The data to decode.
-        * @param int $decoded_len Out parameter with the length of $data that's been decoded.
-        *   Should be ```strlen($data)``` if not truncated.
-        * @return string|string|string|false string the decoded data.
-        *               or string the unencoded data.
-        *               or string the truncated decoded data.
-        *               or false if $data cannot be decoded.
-        */
-       function decode(string $data, int &$decoded_len = 0) {}
-}
-/**
- * A deflate stream supporting deflate, zlib and gzip encodings.
- */
-class Deflate extends \http\Encoding\Stream {
-       /**
-        * Gzip encoding. RFC1952
-        */
-       const TYPE_GZIP = 16;
-       /**
-        * Zlib encoding. RFC1950
-        */
-       const TYPE_ZLIB = 0;
-       /**
-        * Deflate encoding. RFC1951
-        */
-       const TYPE_RAW = 32;
-       /**
-        * Default compression level.
-        */
-       const LEVEL_DEF = 0;
-       /**
-        * Least compression level.
-        */
-       const LEVEL_MIN = 1;
-       /**
-        * Greatest compression level.
-        */
-       const LEVEL_MAX = 9;
-       /**
-        * Default compression strategy.
-        */
-       const STRATEGY_DEF = 0;
-       /**
-        * Filtered compression strategy.
-        */
-       const STRATEGY_FILT = 256;
-       /**
-        * Huffman strategy only.
-        */
-       const STRATEGY_HUFF = 512;
-       /**
-        * Run-length encoding strategy.
-        */
-       const STRATEGY_RLE = 768;
-       /**
-        * Encoding with fixed Huffman codes only.
-        * 
-        * > **A note on the compression strategy:**
-        * >
-        * > The strategy parameter is used to tune the compression algorithm.
-        * >
-        * > Use the value DEFAULT_STRATEGY for normal data, FILTERED for data produced by a filter (or predictor), HUFFMAN_ONLY to force Huffman encoding only (no string match), or RLE to limit match distances to one (run-length encoding).
-        * >
-        * > Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between DEFAULT_STRATEGY and HUFFMAN_ONLY.
-        * >
-        * > RLE is designed to be almost as fast as HUFFMAN_ONLY, but give better compression for PNG image data.
-        * >
-        * > FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications.
-        * >
-        * > The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately.
-        * >
-        * >_Source: [zlib Manual](http://www.zlib.net/manual.html)_
-        */
-       const STRATEGY_FIXED = 1024;
-       /**
-        * Encode data with deflate/zlib/gzip encoding.
-        * 
-        * @param string $data The data to compress.
-        * @param int $flags Any compression tuning flags. See http\Encoding\Stream\Deflate and http\Encoding\Stream constants.
-        * @return string the compressed data.
-        */
-       function encode(string $data, int $flags = 0) {}
-}
-/**
- * A [brotli](https://brotli.org) encoding stream.
- * 
- * > ***NOTE:***
- * > This class has been added in v3.2.0.
- */
-class Enbrotli extends \http\Encoding\Stream {
-       /**
-        * Default compression level.
-        */
-       const LEVEL_DEF = 4;
-       /**
-        * Least compression level.
-        */
-       const LEVEL_MIN = 1;
-       /**
-        * Greatest compression level.
-        */
-       const LEVEL_MAX = 11;
-       /**
-        * Default window bits.
-        */
-       const WBITS_DEF = 352;
-       /**
-        * Minimum window bits.
-        */
-       const WBITS_MIN = 160;
-       /**
-        * Maximum window bits.
-        */
-       const WBITS_MAX = 384;
-       /**
-        * Default compression mode.
-        */
-       const MODE_GENERIC = 0;
-       /**
-        * Compression mode for UTF-8 formatted text.
-        */
-       const MODE_TEXT = 4096;
-       /**
-        * Compression mode used in WOFF 2.0.
-        */
-       const MODE_FONT = 8192;
-       /**
-        * Encode data with brotli encoding.
-        * 
-        * @param string $data The data to compress.
-        * @param int $flags Any compression tuning flags. See http\Encoding\Stream\Enbrotli and http\Encoding\Stream constants.
-        * @return string the compressed data.
-        */
-       function encode(string $data, int $flags = 0) {}
-}
-/**
- * A inflate stream supporting deflate, zlib and gzip encodings.
- */
-class Inflate extends \http\Encoding\Stream {
-       /**
-        * Decode deflate/zlib/gzip encoded data.
-        * 
-        * @param string $data The data to uncompress.
-        * @return string the uncompressed data.
-        */
-       function decode(string $data) {}
-}
-namespace http\Env;
-/**
- * The http\Env\Request class' instances represent the server's current HTTP request.
- * 
- * See http\Message for inherited members.
- */
-class Request extends \http\Message {
-       /**
-        * The request's query parameters. ($_GET)
-        * 
-        * @protected
-        * @var \http\QueryString
-        */
-       protected $query = NULL;
-       /**
-        * The request's form parameters. ($_POST)
-        * 
-        * @protected
-        * @var \http\QueryString
-        */
-       protected $form = NULL;
-       /**
-        * The request's form uploads. ($_FILES)
-        * 
-        * @protected
-        * @var array
-        */
-       protected $files = NULL;
-       /**
-        * The request's cookies. ($_COOKIE)
-        * 
-        * @protected
-        * @var array
-        */
-       protected $cookie = NULL;
-       /**
-        * Create an instance of the server's current HTTP request.
-        * 
-        * Upon construction, the http\Env\Request acquires http\QueryString instances of query parameters ($\_GET) and form parameters ($\_POST).
-        * 
-        * It also compiles an array of uploaded files ($\_FILES) more comprehensive than the original $\_FILES array, see http\Env\Request::getFiles() for that matter.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        */
-       function __construct() {}
-       /**
-        * Retrieve an URL query value ($_GET).
-        * 
-        * See http\QueryString::get() and http\QueryString::TYPE_* constants.
-        * 
-        * @param string $name The key to retrieve the value for.
-        * @param mixed $type The type to cast the value to. See http\QueryString::TYPE_* constants.
-        * @param mixed $defval The default value to return if the key $name does not exist.
-        * @param bool $delete Whether to delete the entry from the querystring after retrieval.
-        * @return \http\QueryString|string|mixed|mixed|string \http\QueryString if called without arguments.
-        *               or string the whole querystring if $name is of zero length.
-        *               or mixed $defval if the key $name does not exist.
-        *               or mixed the querystring value cast to $type if $type was specified and the key $name exists.
-        *               or string the querystring value if the key $name exists and $type is not specified or equals http\QueryString::TYPE_STRING.
-        */
-       function getCookie(string $name = NULL, $type = NULL, $defval = NULL, bool $delete = false) {}
-       /**
-        * Retrieve the uploaded files list ($_FILES).
-        * 
-        * @return array the consolidated upload files array.
-        */
-       function getFiles() {}
-       /**
-        * Retrieve a form value ($_POST).
-        * 
-        * See http\QueryString::get() and http\QueryString::TYPE_* constants.
-        * 
-        * @param string $name The key to retrieve the value for.
-        * @param mixed $type The type to cast the value to. See http\QueryString::TYPE_* constants.
-        * @param mixed $defval The default value to return if the key $name does not exist.
-        * @param bool $delete Whether to delete the entry from the querystring after retrieval.
-        * @return \http\QueryString|string|mixed|mixed|string \http\QueryString if called without arguments.
-        *               or string the whole querystring if $name is of zero length.
-        *               or mixed $defval if the key $name does not exist.
-        *               or mixed the querystring value cast to $type if $type was specified and the key $name exists.
-        *               or string the querystring value if the key $name exists and $type is not specified or equals http\QueryString::TYPE_STRING.
-        */
-       function getForm(string $name = NULL, $type = NULL, $defval = NULL, bool $delete = false) {}
-       /**
-        * Retrieve an URL query value ($_GET).
-        * 
-        * See http\QueryString::get() and http\QueryString::TYPE_* constants.
-        * 
-        * @param string $name The key to retrieve the value for.
-        * @param mixed $type The type to cast the value to. See http\QueryString::TYPE_* constants.
-        * @param mixed $defval The default value to return if the key $name does not exist.
-        * @param bool $delete Whether to delete the entry from the querystring after retrieval.
-        * @return \http\QueryString|string|mixed|mixed|string \http\QueryString if called without arguments.
-        *               or string the whole querystring if $name is of zero length.
-        *               or mixed $defval if the key $name does not exist.
-        *               or mixed the querystring value cast to $type if $type was specified and the key $name exists.
-        *               or string the querystring value if the key $name exists and $type is not specified or equals http\QueryString::TYPE_STRING.
-        */
-       function getQuery(string $name = NULL, $type = NULL, $defval = NULL, bool $delete = false) {}
-}
-/**
- * The http\Env\Response class' instances represent the server's current HTTP response.
- * 
- * See http\Message for inherited members.
- */
-class Response extends \http\Message {
-       /**
-        * Do not use content encoding.
-        */
-       const CONTENT_ENCODING_NONE = 0;
-       /**
-        * Support "Accept-Encoding" requests with gzip and deflate encoding.
-        */
-       const CONTENT_ENCODING_GZIP = 1;
-       /**
-        * No caching info available.
-        */
-       const CACHE_NO = 0;
-       /**
-        * The cache was hit.
-        */
-       const CACHE_HIT = 1;
-       /**
-        * The cache was missed.
-        */
-       const CACHE_MISS = 2;
-       /**
-        * A request instance which overrides the environments default request.
-        * 
-        * @protected
-        * @var \http\Env\Request
-        */
-       protected $request = NULL;
-       /**
-        * The response's MIME content type.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $contentType = NULL;
-       /**
-        * The response's MIME content disposition.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $contentDisposition = NULL;
-       /**
-        * See http\Env\Response::CONTENT_ENCODING_* constants.
-        * 
-        * @protected
-        * @var int
-        */
-       protected $contentEncoding = NULL;
-       /**
-        * How the client should treat this response in regards to caching.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $cacheControl = NULL;
-       /**
-        * A custom ETag.
-        * 
-        * @protected
-        * @var string
-        */
-       protected $etag = NULL;
-       /**
-        * A "Last-Modified" time stamp.
-        * 
-        * @protected
-        * @var int
-        */
-       protected $lastModified = NULL;
-       /**
-        * Any throttling delay.
-        * 
-        * @protected
-        * @var int
-        */
-       protected $throttleDelay = NULL;
-       /**
-        * The chunk to send every $throttleDelay seconds.
-        * 
-        * @protected
-        * @var int
-        */
-       protected $throttleChunk = NULL;
-       /**
-        * The response's cookies.
-        * 
-        * @protected
-        * @var array
-        */
-       protected $cookies = NULL;
-       /**
-        * Create a new env response message instance.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        */
-       function __construct() {}
-       /**
-        * Output buffer handler.
-        * Appends output data to the body.
-        * 
-        * @param string $data The data output.
-        * @param int $ob_flags Output buffering flags passed from the output buffering control layer.
-        * @return bool success.
-        */
-       function __invoke(string $data, int $ob_flags = 0) {}
-       /**
-        * Manually test the header $header_name of the environment's request for a cache hit.
-        * http\Env\Response::send() checks that itself, though.
-        * 
-        * @param string $header_name The request header to test.
-        * @return int a http\Env\Response::CACHE_* constant.
-        */
-       function isCachedByEtag(string $header_name = "If-None-Match") {}
-       /**
-        * Manually test the header $header_name of the environment's request for a cache hit.
-        * http\Env\Response::send() checks that itself, though.
-        * 
-        * @param string $header_name The request header to test.
-        * @return int a http\Env\Response::CACHE_* constant.
-        */
-       function isCachedByLastModified(string $header_name = "If-Modified-Since") {}
-       /**
-        * Send the response through the SAPI or $stream.
-        * Flushes all output buffers.
-        * 
-        * @param resource $stream A writable stream to send the response through.
-        * @return bool success.
-        */
-       function send($stream = NULL) {}
-       /**
-        * Make suggestions to the client how it should cache the response.
-        * 
-        * @param string $cache_control (A) "Cache-Control" header value(s).
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Env\Response self.
-        */
-       function setCacheControl(string $cache_control) {}
-       /**
-        * Set the reponse's content disposition parameters.
-        * 
-        * @param array $disposition_params MIME content disposition as http\Params array.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Env\Response self.
-        */
-       function setContentDisposition(array $disposition_params) {}
-       /**
-        * Enable support for "Accept-Encoding" requests with deflate or gzip.
-        * The response will be compressed if the client indicates support and wishes that.
-        * 
-        * @param int $content_encoding See http\Env\Response::CONTENT_ENCODING_* constants.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Env\Response self.
-        */
-       function setContentEncoding(int $content_encoding) {}
-       /**
-        * Set the MIME content type of the response.
-        * 
-        * @param string $content_type The response's content type.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Env\Response self.
-        */
-       function setContentType(string $content_type) {}
-       /**
-        * Add cookies to the response to send.
-        * 
-        * @param mixed $cookie The cookie to send.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return \http\Env\Response self.
-        */
-       function setCookie($cookie) {}
-       /**
-        * Override the environment's request.
-        * 
-        * @param \http\Message $env_request The overriding request message.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Env\Response self.
-        */
-       function setEnvRequest(\http\Message $env_request) {}
-       /**
-        * Set a custom ETag.
-        * 
-        * > ***NOTE:***
-        * > This will be used for caching and pre-condition checks.
-        * 
-        * @param string $etag A ETag.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Env\Response self.
-        */
-       function setEtag(string $etag) {}
-       /**
-        * Set a custom last modified time stamp.
-        * 
-        * > ***NOTE:***
-        * > This will be used for caching and pre-condition checks.
-        * 
-        * @param int $last_modified A unix timestamp.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return \http\Env\Response self.
-        */
-       function setLastModified(int $last_modified) {}
-       /**
-        * Enable throttling.
-        * Send $chunk_size bytes every $delay seconds.
-        * 
-        * > ***NOTE:***
-        * > If you need throttling by regular means, check for other options in your stack, because this method blocks the executing process/thread until the response has completely been sent.
-        * 
-        * @param int $chunk_size Bytes to send.
-        * @param float $delay Seconds to sleep.
-        * @return \http\Env\Response self.
-        */
-       function setThrottleRate(int $chunk_size, float $delay = 1) {}
-}
-/**
- * URL class using the HTTP environment by default.
- * 
- * > ***NOTE:***
- * > This class has been added in v3.0.0.
- * 
- * Always adds http\Url::FROM_ENV to the $flags constructor argument. See also http\Url.
- */
-class Url extends \http\Url {
-}
-namespace http\Exception;
-/**
- * A bad conversion (e.g. character conversion) was encountered.
- */
-class BadConversionException extends \DomainException implements \http\Exception {
-}
-/**
- * A bad HTTP header was encountered.
- */
-class BadHeaderException extends \DomainException implements \http\Exception {
-}
-/**
- * A bad HTTP message was encountered.
- */
-class BadMessageException extends \DomainException implements \http\Exception {
-}
-/**
- * A method was called on an object, which was in an invalid or unexpected state.
- */
-class BadMethodCallException extends \BadMethodCallException implements \http\Exception {
-}
-/**
- * A bad querystring was encountered.
- */
-class BadQueryStringException extends \DomainException implements \http\Exception {
-}
-/**
- * A bad HTTP URL was encountered.
- */
-class BadUrlException extends \DomainException implements \http\Exception {
-}
-/**
- * One or more invalid arguments were passed to a method.
- */
-class InvalidArgumentException extends \InvalidArgumentException implements \http\Exception {
-}
-/**
- * A generic runtime exception.
- */
-class RuntimeException extends \RuntimeException implements \http\Exception {
-}
-/**
- * An unexpected value was encountered.
- */
-class UnexpectedValueException extends \UnexpectedValueException implements \http\Exception {
-}
-namespace http\Header;
-/**
- * The parser which is underlying http\Header and http\Message.
- * 
- * > ***NOTE:***
- * > This class has been added in v2.3.0.
- */
-class Parser  {
-       /**
-        * Finish up parser at end of (incomplete) input.
-        */
-       const CLEANUP = 1;
-       /**
-        * Parse failure.
-        */
-       const STATE_FAILURE = -1;
-       /**
-        * Expecting HTTP info (request/response line) or headers.
-        */
-       const STATE_START = 0;
-       /**
-        * Expecting a key or already parsing a key.
-        */
-       const STATE_KEY = 1;
-       /**
-        * Expecting a value or already parsing the value.
-        */
-       const STATE_VALUE = 2;
-       /**
-        * At EOL of an header, checking whether a folded header line follows.
-        */
-       const STATE_VALUE_EX = 3;
-       /**
-        * A header was completed.
-        */
-       const STATE_HEADER_DONE = 4;
-       /**
-        * Finished parsing the headers.
-        * 
-        * > ***NOTE:***
-        * > Most of this states won't be returned to the user, because the parser immediately jumps to the next expected state.
-        */
-       const STATE_DONE = 5;
-       /**
-        * Retrieve the current state of the parser.
-        * See http\Header\Parser::STATE_* constants.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @return int http\Header\Parser::STATE_* constant.
-        */
-       function getState() {}
-       /**
-        * Parse a string.
-        * 
-        * @param string $data The (part of the) header to parse.
-        * @param int $flags Any combination of [parser flags](http/Header/Parser#Parser.flags:).
-        * @param array $header Successfully parsed headers.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return int http\Header\Parser::STATE_* constant.
-        */
-       function parse(string $data, int $flags, array &$header = NULL) {}
-       /**
-        * Parse a stream.
-        * 
-        * @param resource $stream The header stream to parse from.
-        * @param int $flags Any combination of [parser flags](http/Header/Parser#Parser.flags:).
-        * @param array $headers The headers parsed.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return int http\Header\Parser::STATE_* constant.
-        */
-       function stream($stream, int $flags, array &$headers) {}
-}
-namespace http\Message;
-/**
- * The message body, represented as a PHP (temporary) stream.
- * 
- * > ***NOTE:***
- * > Currently, http\Message\Body::addForm() creates multipart/form-data bodies.
- */
-class Body implements \Serializable {
-       /**
-        * Create a new message body, optionally referencing $stream.
-        * 
-        * @param resource $stream A stream to be used as message body.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        */
-       function __construct($stream = NULL) {}
-       /**
-        * String cast handler.
-        * 
-        * @return string the message body.
-        */
-       function __toString() {}
-       /**
-        * Add form fields and files to the message body.
-        * 
-        * > ***NOTE:***
-        * > Currently, http\Message\Body::addForm() creates "multipart/form-data" bodies.
-        * 
-        * @param array $fields List of form fields to add.
-        * @param array $files List of form files to add.
-        * 
-        * $fields must look like:
-        * 
-        *     [
-        *       "field_name" => "value",
-        *       "multi_field" => [
-        *         "value1",
-        *         "value2"
-        *       ]
-        *     ]
-        * 
-        * $files must look like:
-        * 
-        *     [
-        *       [
-        *         "name" => "field_name",
-        *         "type" => "content/type",
-        *         "file" => "/path/to/file.ext"
-        *       ], [
-        *         "name" => "field_name2",
-        *         "type" => "text/plain",
-        *         "file" => "file.ext",
-        *         "data" => "string"
-        *       ], [
-        *         "name" => "field_name3",
-        *         "type" => "image/jpeg",
-        *         "file" => "file.ext",
-        *         "data" => fopen("/home/mike/Pictures/mike.jpg","r")
-        *     ]
-        * 
-        * As you can see, a file structure must contain a "file" entry, which holds a file path, and an optional "data" entry, which may either contain a resource to read from or the actual data as string.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        * @return \http\Message\Body self.
-        */
-       function addForm(array $fields = NULL, array $files = NULL) {}
-       /**
-        * Add a part to a multipart body.
-        * 
-        * @param \http\Message $part The message part.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        * @return \http\Message\Body self.
-        */
-       function addPart(\http\Message $part) {}
-       /**
-        * Append plain bytes to the message body.
-        * 
-        * @param string $data The data to append to the body.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\RuntimeException
-        * @return \http\Message\Body self.
-        */
-       function append(string $data) {}
-       /**
-        * Retrieve the ETag of the body.
-        * 
-        * @return string|string|false string an Apache style ETag of inode, mtime and size in hex concatenated by hyphens if the message body stream is stat-able.
-        *               or string a content hash (which algorithm is determined by INI http.etag.mode) if the stream is not stat-able.
-        *               or false if http.etag.mode is not a known hash algorithm.
-        */
-       function etag() {}
-       /**
-        * Retrieve any boundary of the message body.
-        * See http\Message::splitMultipartBody().
-        * 
-        * @return string|NULL string the message body boundary.
-        *               or NULL if this message body has no boundary.
-        */
-       function getBoundary() {}
-       /**
-        * Retrieve the underlying stream resource.
-        * 
-        * @return resource the underlying stream.
-        */
-       function getResource() {}
-       /**
-        * Implements Serializable.
-        * Alias of http\Message\Body::__toString().
-        * 
-        * @return string serialized message body.
-        */
-       function serialize() {}
-       /**
-        * Stat size, atime, mtime and/or ctime.
-        * 
-        * @param string $field A single stat field to retrieve.
-        * @return int|object int the requested stat field.
-        *               or object stdClass instance holding all four stat fields.
-        */
-       function stat(string $field = NULL) {}
-       /**
-        * Stream the message body through a callback.
-        * 
-        * @param callable $callback The callback of the form function(http\Message\Body $from, string $data).
-        * @param int $offset Start to stream from this offset.
-        * @param int $maxlen Stream at most $maxlen bytes, or all if $maxlen is less than 1.
-        * @return \http\Message\Body self.
-        */
-       function toCallback(callable $callback, int $offset = 0, int $maxlen = 0) {}
-       /**
-        * Stream the message body into another stream $stream, starting from $offset, streaming $maxlen at most.
-        * 
-        * @param resource $stream The resource to write to.
-        * @param int $offset The starting offset.
-        * @param int $maxlen The maximum amount of data to stream. All content if less than 1.
-        * @return \http\Message\Body self.
-        */
-       function toStream($stream, int $offset = 0, int $maxlen = 0) {}
-       /**
-        * Retrieve the message body serialized to a string.
-        * Alias of http\Message\Body::__toString().
-        * 
-        * @return string message body.
-        */
-       function toString() {}
-       /**
-        * Implements Serializable.
-        * 
-        * @param string $serialized The serialized message body.
-        */
-       function unserialize($serialized) {}
-}
-/**
- * The parser which is underlying http\Message.
- * 
- * > ***NOTE:***
- * > This class was added in v2.2.0.
- */
-class Parser  {
-       /**
-        * Finish up parser at end of (incomplete) input.
-        */
-       const CLEANUP = 1;
-       /**
-        * Soak up the rest of input if no entity length is deducible.
-        */
-       const DUMB_BODIES = 2;
-       /**
-        * Redirect messages do not contain any body despite of indication of such.
-        */
-       const EMPTY_REDIRECTS = 4;
-       /**
-        * Continue parsing while input is available.
-        */
-       const GREEDY = 8;
-       /**
-        * Parse failure.
-        */
-       const STATE_FAILURE = -1;
-       /**
-        * Expecting HTTP info (request/response line) or headers.
-        */
-       const STATE_START = 0;
-       /**
-        * Parsing headers.
-        */
-       const STATE_HEADER = 1;
-       /**
-        * Completed parsing headers.
-        */
-       const STATE_HEADER_DONE = 2;
-       /**
-        * Parsing the body.
-        */
-       const STATE_BODY = 3;
-       /**
-        * Soaking up all input as body.
-        */
-       const STATE_BODY_DUMB = 4;
-       /**
-        * Reading body as indicated by `Content-Length` or `Content-Range`.
-        */
-       const STATE_BODY_LENGTH = 5;
-       /**
-        * Parsing `chunked` encoded body.
-        */
-       const STATE_BODY_CHUNKED = 6;
-       /**
-        * Finished parsing the body.
-        */
-       const STATE_BODY_DONE = 7;
-       /**
-        * Updating Content-Length based on body size.
-        */
-       const STATE_UPDATE_CL = 8;
-       /**
-        * Finished parsing the message.
-        * 
-        * > ***NOTE:***
-        * > Most of this states won't be returned to the user, because the parser immediately jumps to the next expected state.
-        */
-       const STATE_DONE = 9;
-       /**
-        * Retrieve the current state of the parser.
-        * See http\Message\Parser::STATE_* constants.
-        * 
-        * @throws \http\Exception\InvalidArgumentException
-        * @return int http\Message\Parser::STATE_* constant.
-        */
-       function getState() {}
-       /**
-        * Parse a string.
-        * 
-        * @param string $data The (part of the) message to parse.
-        * @param int $flags Any combination of [parser flags](http/Message/Parser#Parser.flags:).
-        * @param \http\Message $message The current state of the message parsed.
-        * @throws \http\Exception\InvalidArgumentException
-        * @return int http\Message\Parser::STATE_* constant.
-        */
-       function parse(string $data, int $flags, \http\Message &$message) {}
-       /**
-        * Parse a stream.
-        * 
-        * @param resource $stream The message stream to parse from.
-        * @param int $flags Any combination of [parser flags](http/Message/Parser#Parser.flags:).
-        * @param \http\Message $message The current state of the message parsed.
-        * @throws \http\Exception\InvalidArgumentException
-        * @throws \http\Exception\UnexpectedValueException
-        * @return int http\Message\Parser::STATE_* constant.
-        */
-       function stream($stream, int $flags, \http\Message &$message) {}
-}
index 8e4f04cecce318581066c1d49c373e8ebf53c495..3ed788a6af07b6ef00c0d52d8be25f9c88a96f52 100644 (file)
@@ -14,69 +14,32 @@ use seekat\Exception\InvalidArgumentException;
 class API implements IteratorAggregate, Countable {
        /**
         * API version
-        * @var int
         */
-       private $version = 3;
-
-       /**
-        * The current API endpoint URL
-        * @var Url
-        */
-       private $url;
+       private int $version = 3;
 
        /**
         * Default headers to send out to the API endpoint
-        * @var array
         */
-       private $headers;
+       private array $headers;
 
        /**
         * Current endpoints links
-        * @var Links
         */
-       private $links;
+       private ?Links $links = null;
 
        /**
         * Current endpoint data's Content-Type
-        * @var API\ContentType
         */
-       private $type;
+       private API\ContentType $type;
 
        /**
         * Current endpoint's data
-        * @var array|object
-        */
-       private $data;
-
-       /**
-        * Logger
-        * @var LoggerInterface
-        */
-       private $logger;
-
-       /**
-        * Cache
-        * @var Call\Cache\Service
-        */
-       private $cache;
-
-       /**
-        * Promisor
-        * @var Future
-        */
-       private $future;
-
-       /**
-        * The HTTP client
-        * @var Client
         */
-       private $client;
+       private mixed $data = null;
 
        /**
         * Create a new API endpoint root
         *
-        * @codeCoverageIgnore
-        *
         * @param Future $future pretending to fulfill promises
         * @param array $headers Standard request headers, defaults to ["Accept" => "application/vnd.github.v3+json"]
         * @param Url $url The API's endpoint, defaults to https://api.github.com
@@ -84,12 +47,12 @@ class API implements IteratorAggregate, Countable {
         * @param LoggerInterface $log A logger
         * @param Call\Cache\Service $cache A cache
         */
-       function __construct(Future $future, array $headers = null, Url $url = null, Client $client = null, LoggerInterface $log = null, Call\Cache\Service $cache = null) {
-               $this->future = $future;
-               $this->cache = $cache;
-               $this->logger = $log ?? new NullLogger;
-               $this->url = $url ?? new Url("https://api.github.com");
-               $this->client = $client ?? new Client;
+       function __construct(private readonly Future $future,
+                                                array $headers = null,
+                                                private Url $url = new Url("https://api.github.com"),
+                                                private readonly Client $client = new Client,
+                                                private readonly LoggerInterface $logger = new NullLogger,
+                                                private readonly Call\Cache\Service $cache = new Call\Cache\Service\Hollow) {
                $this->type = new ContentType($this->version, "json");
                $this->headers = (array) $headers + [
                        "Accept" => $this->type->getContentType()
@@ -102,8 +65,8 @@ class API implements IteratorAggregate, Countable {
         * @param string|int $seg The "path" element to ascend into
         * @return API Endpoint clone referring to {$parent}/{$seg}
         */
-       function __get($seg) : API {
-               if (substr($seg, -4) === "_url") {
+       function __get(string|int $seg) : API {
+               if (str_ends_with($seg, "_url")) {
                        $url = new Url(uri_template($this->data->$seg));
                        $that = $this->withUrl($url);
                        $seg = basename($that->url->path);
@@ -158,8 +121,8 @@ class API implements IteratorAggregate, Countable {
         * @return mixed The promise of the generator's return value
         * @throws InvalidArgumentException
         */
-       function __invoke($cbg) {
-               $this->logger->debug(__FUNCTION__);
+       function __invoke(callable|Generator $cbg) {
+               $this->logger->debug(__METHOD__, [$cbg]);
 
                $consumer = new Consumer($this->getFuture(), function() {
                                $this->client->send();
@@ -235,38 +198,27 @@ class API implements IteratorAggregate, Countable {
                return $count;
        }
 
-       /**
-        * @return Url
-        */
        function getUrl() : Url {
                return $this->url;
        }
 
-       /**
-        * @return LoggerInterface
-        */
        function getLogger() : LoggerInterface {
                return $this->logger;
        }
 
-       /**
-        * @return Future
-        */
-       function getFuture() {
+       function getFuture() : Future {
                return $this->future;
        }
 
-       /**
-        * @return Client
-        */
        public function getClient(): Client {
                return $this->client;
        }
 
-       /**
-        * @return array|object
-        */
-       function getData() {
+       public function getCache() : Call\Cache\Service {
+               return $this->cache;
+       }
+
+       function getData() : mixed {
                return $this->data;
        }
 
@@ -275,7 +227,7 @@ class API implements IteratorAggregate, Countable {
         *
         * @return null|Links
         */
-       function getLinks() {
+       function getLinks() : ?Links {
                return $this->links;
        }
 
@@ -294,7 +246,7 @@ class API implements IteratorAggregate, Countable {
        function export() : array {
                $data = $this->data;
                $url = clone $this->url;
-               $type = $this->type ? clone $this->type : null;
+               $type = clone $this->type;
                $links = $this->links ? clone $this->links : null;
                $headers = $this->headers;
                return compact("url", "data", "type", "links", "headers");
@@ -322,7 +274,7 @@ class API implements IteratorAggregate, Countable {
         * @param mixed $data
         * @return API clone
         */
-       function withData($data) : API {
+       function withData(mixed $data) : API {
                $that = clone $this;
                $that->data = $data;
                return $that;
@@ -349,7 +301,7 @@ class API implements IteratorAggregate, Countable {
         * @param mixed $value
         * @return API clone
         */
-       function withHeader(string $name, $value) : API {
+       function withHeader(string $name, mixed $value) : API {
                $that = clone $this;
                if (isset($value)) {
                        $that->headers[$name] = $value;
@@ -387,8 +339,8 @@ class API implements IteratorAggregate, Countable {
         * @param array $headers The request's additional HTTP headers
         * @return mixed promise
         */
-       function head($args = null, array $headers = null, $cache = null) {
-               return $this->request("HEAD", $args, null, $headers, $cache);
+       function head($args = null, array $headers = null) {
+               return $this->request("HEAD", $args, null, $headers);
        }
 
        /**
@@ -398,8 +350,8 @@ class API implements IteratorAggregate, Countable {
         * @param array $headers The request's additional HTTP headers
         * @return mixed promise
         */
-       function get($args = null, array $headers = null, $cache = null) {
-               return $this->request("GET", $args, null, $headers, $cache);
+       function get($args = null, array $headers = null) {
+               return $this->request("GET", $args, null, $headers);
        }
 
        /**
@@ -497,12 +449,11 @@ class API implements IteratorAggregate, Countable {
         *
         * @param string $method The HTTP request method
         * @param mixed $args The HTTP query string parameters
-        * @param mixed $body Thee HTTP message's body
-        * @param array $headers The request's additional HTTP headers
-        * @param Call\Cache\Service $cache
+        * @param mixed $body The HTTP message's body
+        * @param ?array $headers The request's additional HTTP headers
         * @return mixed promise
         */
-       private function request(string $method, $args = null, $body = null, array $headers = null, Call\Cache\Service $cache = null) {
+       private function request(string $method, $args = null, $body = null, array $headers = null) {
                if (isset($this->data)) {
                        $this->logger->debug("request -> resolve", [
                                "method"  => $method,
@@ -512,7 +463,7 @@ class API implements IteratorAggregate, Countable {
                                "headers" => $headers,
                        ]);
 
-                       return Future\resolve($this->future, $this);
+                       return $this->future->resolve($this);
                }
 
                $url = $this->url->mod(["query" => new QueryString($args)]);
@@ -527,6 +478,6 @@ class API implements IteratorAggregate, Countable {
                        "headers" => $headers,
                ]);
 
-               return (new Call\Deferred($this, $request, $cache ?: $this->cache))();
+               return (new Call\Deferred($this, $request, $this->cache))();
        }
 }
index 38b1559f6172b2bffe7d28586c44e0c8d09ecc96..a913bdaffb6c49c4f7031576342af864960a2f84 100644 (file)
@@ -6,19 +6,7 @@ use http\Url;
 use seekat\API;
 
 final class Call {
-       /**
-        * @var API
-        */
-       private $api;
-
-       /**
-        * @var string
-        */
-       private $call;
-
-       function __construct(API $api, string $call) {
-               $this->api = $api;
-               $this->call = $call;
+       function __construct(private readonly API $api, private readonly string $call) {
        }
 
        function __invoke(array $args) {
index 3947259b51d5a09ef57a7157599bc3c6d50f3e9c..1b7e327e84c5f242506e831c0f6d2c4488b82b3d 100644 (file)
@@ -4,22 +4,17 @@ namespace seekat\API\Call;
 
 use http\Client\Request;
 use http\Client\Response;
+use Psr\Log\LoggerInterface;
 use seekat\API\Call\Cache\Control;
 use seekat\API\Call\Cache\Service;
 use seekat\API\Call\Cache\Service\Hollow;
 
 
 final class Cache {
-       /**
-        * @var Service
-        */
-       private $cache;
-
-       /**
-        * @param Service $cache
-        */
-       public function __construct(Service $cache = null) {
-               $this->cache = $cache ?? new Hollow;
+       public function __construct(
+               private readonly LoggerInterface $logger,
+               private readonly Service $cache = new Hollow
+       ) {
        }
 
        /**
@@ -31,15 +26,18 @@ final class Cache {
        public function save(Request $request, Response $response) : bool {
                $ctl = new Control($request);
                if (!$ctl->isValid()) {
+                       $this->logger->warning("cache -> save = invalid key", compact("ctl"));
                        return false;
                }
 
                $time = time();
                if ($time - 1 <= $response->getHeader("X-Cache-Time")) {
+                       $this->logger->info("cache -> save = no", compact("time"));
                        return true;
                }
                $response->setHeader("X-Cache-Time", $time);
 
+               $this->logger->info("cache -> save = yes", compact("time"));
                return $this->cache->store($ctl->getKey(), $response);
        }
 
@@ -52,10 +50,12 @@ final class Cache {
        public function load(Request $request, Response &$response = null) : bool {
                $ctl = new Control($request);
                if (!$ctl->isValid()) {
+                       $this->logger->warning("cache -> load = invalid key", compact("ctl"));
                        return false;
                }
 
                if (!$this->cache->fetch($ctl->getKey(), $response)) {
+                       $this->logger->info("cache -> load = no");
                        return false;
                }
                if ($ctl->isStale($response)) {
@@ -65,9 +65,11 @@ final class Cache {
                        if (($etag = $response->getHeader("ETag"))) {
                                $request->setOptions(["etag" => $etag]);
                        }
+                       $this->logger->info("cache -> load = stale");
                        return false;
                }
                $response->setHeader("X-Cache-Hit", $response->getHeader("X-Cache-Hit") + 1);
+               $this->logger->info("cache -> load = yes");
                return true;
        }
 
@@ -80,24 +82,30 @@ final class Cache {
        public function update(Request $request, Response &$response) : bool {
                $ctl = new Control($request);
                if (!$ctl->isValid()) {
+                       $this->logger->warning("cache -> update = invalid key", compact("ctl"));
                        return false;
                }
 
                if ($response->getResponseCode() !== 304) {
+                       $this->logger->info("cache -> update = yes");
                        return $this->save($request, $response);
                }
 
                /** @var Response $cached */
                if (!$this->cache->fetch($ctl->getKey(), $cached)) {
+                       $this->logger->info("cache -> update = yes; no-exist");
                        return $this->save($request, $response);
                }
 
                if ($response->getHeader("ETag") !== $cached->getHeader("ETag")) {
+                       $this->logger->info("cache -> update = yes; etag");
                        return $this->save($request, $response);
                }
 
-               $cached->setHeader("X-Cache-Update", $cached->getHeader("X-Cache-Update") + 1);
                $response = $cached;
-               return true;
+               $response->setHeader("X-Cache-Update", $cached->getHeader("X-Cache-Update") + 1);
+
+               $this->logger->info("cache -> update = yes; touch");
+               return $this->save($request, $response);
        }
 }
index 7ebac9da53b063c6aa1af463ae82343623ab01a1..a6186f25b668f8d91985175779920b3fee67c007 100644 (file)
@@ -10,10 +10,7 @@ use http\QueryString;
 use http\Url;
 
 final class Control {
-       /**
-        * @var string
-        */
-       private $key;
+       private string $key;
 
        /**
         * @param Request $request
index 31db9e99d7b3c04095218e46f545d3eca7ad241b..57b92378faa9bfaf8746c26557087b19b271ddab 100644 (file)
@@ -7,6 +7,6 @@ use http\Client\Response;
 interface Service {
        function fetch(string $key, Response &$response = null) : bool;
        function store(string $key, Response $response) : bool;
-       function del(string $key);
-       function clear();
+       function del(string $key) : void;
+       function clear() : void;
 }
index f08d6d65b919bb114c4263f489719aa8f723f682..dd81ba352ecaf5b6615901aa01b59b0f6c79df74 100644 (file)
@@ -6,7 +6,7 @@ use http\Client\Response;
 use seekat\API\Call\Cache\Service;
 
 final class Hollow implements Service {
-       private $storage = [];
+       private array $storage = [];
 
        public function fetch(string $key, Response &$response = null) : bool {
                if (isset($this->storage[$key])) {
@@ -21,11 +21,11 @@ final class Hollow implements Service {
                return true;
        }
 
-       public function del(string $key) {
+       public function del(string $key) : void {
                unset($this->storage[$key]);
        }
 
-       public function clear() {
+       public function clear() : void {
                $this->storage = [];
        }
 
index 264cfbd173ea4414eaeeb36324333ab38a0f3c29..fb488ad4006f3bfd470b6b12579c16a7602c04ce 100644 (file)
@@ -8,18 +8,9 @@ use Psr\Cache\CacheItemPoolInterface;
 use seekat\API\Call\Cache\Service;
 
 final class ItemPool implements Service {
-       /**
-        * @var CacheItemPoolInterface
-        */
-       private $cache;
-
-       /**
-        * @var CacheItemInterface
-        */
-       private $item;
+       private ?CacheItemInterface $item;
 
-       public function __construct(CacheItemPoolInterface $cache) {
-               $this->cache = $cache;
+       public function __construct(private readonly CacheItemPoolInterface $cache) {
        }
 
        /**
@@ -46,11 +37,11 @@ final class ItemPool implements Service {
         * @param string $key
         * @throws \Psr\Cache\InvalidArgumentException
         */
-       public function del(string $key) {
+       public function del(string $key) : void {
                $this->cache->deleteItem($key);
        }
 
-       public function clear() {
+       public function clear() : void {
                $this->cache->clear();
        }
 }
index 4358f1f2f17f37233a6df9a612aa206e1f728227..45bd5fe0bc192d6aafbb457393ec7b4906f807cc 100644 (file)
@@ -7,13 +7,7 @@ use Psr\SimpleCache\CacheInterface;
 use seekat\API\Call\Cache\Service;
 
 final class Simple implements Service {
-       /**
-        * @var CacheInterface
-        */
-       private $cache;
-
-       public function __construct(CacheInterface $cache) {
-               $this->cache = $cache;
+       public function __construct(private readonly CacheInterface $cache) {
        }
 
        public function fetch(string $key, Response &$response = null) : bool {
@@ -25,11 +19,11 @@ final class Simple implements Service {
                return $this->cache->set($key, $response);
        }
 
-       public function del(string $key) {
+       public function del(string $key) : void {
                $this->cache->delete($key);
        }
 
-       public function clear() {
+       public function clear() : void {
                $this->cache->clear();
        }
 }
index bfe8c27e4da46dacbcb9f558615a21a7a1ee02ad..331cc2f65526aec5943c6f542c0100cc06703593 100644 (file)
@@ -7,74 +7,34 @@ use Psr\Log\LoggerInterface;
 use seekat\API;
 
 final class Deferred {
-       /**
-        * The response importer
-        *
-        * @var Result
-        */
-       private $result;
-
-       /**
-        * The HTTP client
-        *
-        * @var Client
-        */
-       private $client;
-
-       /**
-        * Request cache
-        *
-        * @var callable
-        */
-       private $cache;
-
-       /**
-        * @var LoggerInterface
-        */
-       private $logger;
-
-       /**
-        * The executed request
-        *
-        * @var Request
-        */
-       private $request;
+       private Result $result;
+       private Client $client;
+       private LoggerInterface $logger;
+       private Cache $cache;
 
        /**
         * The promised response
-        *
-        * @var Response
         */
-       private $response;
+       private ?Response $response = null;
 
        /**
         * @var mixed
         */
-       private $promise;
-
-       /**
-        * @var \Closure
-        */
-       private $resolve;
-
-       /**
-        * @var \Closure
-        */
-       private $reject;
+       private object $promise;
+       private \Closure $resolve;
+       private \Closure $reject;
 
        /**
         * Create a deferred promise for the response of $request
         *
         * @param API $api The endpoint of the request
         * @param Request $request The request to execute
-        * @param Cache\Service $cache
         */
-       function __construct(API $api, Request $request, Cache\Service $cache = null) {
-               $this->request = $request;
+       function __construct(API $api, private readonly Request $request) {
+               $this->result = new Result($api);
                $this->client = $api->getClient();
                $this->logger = $api->getLogger();
-               $this->result = new Result($api);
-               $this->cache = new Cache($cache);
+               $this->cache  = new Cache($this->logger, $api->getCache());
 
                $future = $api->getFuture();
                $context = $future->createContext(function() {
@@ -87,8 +47,8 @@ final class Deferred {
                        }
                });
                $this->promise = $future->getPromise($context);
-               $this->resolve = API\Future\resolver($future, $context);
-               $this->reject = API\Future\rejecter($future, $context);
+               $this->resolve = $future->resolver($context);
+               $this->reject = $future->rejecter($context);
        }
 
        function __invoke() {
@@ -133,12 +93,7 @@ final class Deferred {
                return true;
        }
 
-       /**
-        * Refresh
-        *
-        * @param Response|null $cached
-        */
-       private function refresh(Response $cached = null) {
+       private function refresh(Response $cached = null) : void {
                $this->client->enqueue($this->request, function(Response $response) use($cached) {
                        $this->response = $response;
                        $this->complete();
@@ -157,7 +112,9 @@ final class Deferred {
        /**
         * Completion callback
         */
-       private function complete(string $by = "enqueued") {
+       private function complete(string $by = "enqueued") : void {
+               $this->logger->info("complete -> $by");
+
                if ($this->response) {
                        $this->logger->info("$by -> response", [
                                "url"  => $this->request->getRequestUrl(),
@@ -168,6 +125,7 @@ final class Deferred {
                                $this->cache->update($this->request, $this->response);
                                ($this->resolve)(($this->result)($this->response));
                        } catch (\Throwable $e) {
+                               $this->logger->warning("$by -> cache", ["exception" => $e]);
                                ($this->reject)($e);
                        }
                } else {
index c1cee55e6a32edcb02ee6304ee37f38699afde48..92b7dae4572a6bdbec243c57fa822b7bdbd946e9 100644 (file)
@@ -36,11 +36,9 @@ final class Result {
        }
 
        /**
-        * @param Response $response
-        * @return null|API\Links
         * @throws RequestException
         */
-       private function checkResponseMeta(Response $response) {
+       private function checkResponseMeta(Response $response) : API\Links {
                if ($response->getResponseCode() >= 400) {
                        $e = new RequestException($response);
 
@@ -59,11 +57,9 @@ final class Result {
        }
 
        /**
-        * @param Response $response
-        * @return API\ContentType
         * @throws RequestException
         */
-       private function checkResponseType(Response $response) {
+       private function checkResponseType(Response $response) : API\ContentType {
                if (!($type = $response->getHeader("Content-Type", Header::class))) {
                        $e = new RequestException($response);
 
@@ -78,12 +74,9 @@ final class Result {
        }
 
        /**
-        * @param Response $response
-        * @param API\ContentType $type
-        * @return mixed
         * @throws \Exception
         */
-       private function checkResponseBody(Response $response, API\ContentType $type) {
+       private function checkResponseBody(Response $response, API\ContentType $type) : mixed {
                try {
                        $data = $type->decode($response->getBody());
                } catch (\Exception $e) {
index 3af614caa9355335c70278f36395f2f5449f8d17..8db2b4d614c86993c0e887a14cbe3eda039a1fdc 100644 (file)
@@ -8,64 +8,37 @@ use seekat\API;
 use seekat\Exception\{function exception};
 
 final class Consumer {
-       /**
-        * Loop
-        * @var callable
-        */
-       private $loop;
-
        /**
         * The return value of the generator
         * @var mixed
         */
-       private $result;
+       private mixed $result = null;
 
        /**
         * Cancellation flag
-        * @var bool
-        */
-       private $cancelled = false;
-
-       /**
-        * @var Future
-        */
-       private $future;
-
-       /**
-        * @var mixed
-        */
-       private $context;
-
-       /**
-        * @var \Closure
         */
-       private $resolve;
+       private bool $cancelled = false;
 
        /**
-        * @var \Closure
+        * Promise
         */
-       private $reject;
+       private object $promise;
 
-       /**
-        * @var \Closure
-        */
-       private $reduce;
+       private \Closure $resolve;
+       private \Closure $reject;
+       private \Closure $reduce;
 
        /**
         * Create a new generator consumer
-        * @param Future $future
-        * @param callable $loop
         */
-       function __construct(Future $future, callable $loop) {
-               $this->loop = $loop;
-
-               $this->future = $future;
-               $this->context = $future->createContext(function() {
+       function __construct(private readonly Future $future, private readonly \Closure $loop) {
+               $context = $future->createContext(function() {
                        $this->cancelled = true;
                });
-               $this->resolve = API\Future\resolver($future, $this->context);
-               $this->reject = API\Future\rejecter($future, $this->context);
-               $this->reduce = API\Future\reducer($future, $this->context);
+               $this->promise = $future->getPromise($context);
+               $this->resolve = $future->resolver($context);
+               $this->reject = $future->rejecter($context);
+               $this->reduce = $future->reducer();
        }
 
        /**
@@ -74,7 +47,7 @@ final class Consumer {
         * @param Generator $gen
         * @return mixed promise
         */
-       function __invoke(Generator $gen) {
+       function __invoke(Generator $gen) : mixed {
                $this->cancelled = false;
                foreach ($gen as $promise) {
                        if ($this->cancelled) {
@@ -85,15 +58,16 @@ final class Consumer {
 
                if ($this->cancelled) {
                        ($this->reject)("Cancelled");
-               } else {
+               } else if (!$gen->valid()) {
                        try {
                                $this->result = $gen->getReturn();
                        } catch (Exception $e) {
+                               assert($e->getMessage() === "Cannot get return value of a generator that hasn't returned");
                        }
-                       ($this->resolve)($this->result);
                }
+               ($this->resolve)($this->result);
 
-               return $this->context->promise();
+               return $this->promise;
        }
 
        /**
@@ -102,7 +76,7 @@ final class Consumer {
         * @param mixed $promise
         * @param Generator $gen
         */
-       private function give($promise, Generator $gen) {
+       private function give(mixed $promise, Generator $gen) : void {
                if ($promise instanceof \Traversable) {
                        $promise = iterator_to_array($promise);
                }
index d6cd7c69dd8cddab8e419378a663e61b5227008d..7aa1043db4d9ab0f2fcfbb3dde0c354810397db5 100644 (file)
@@ -7,21 +7,17 @@ use http\Message\Body;
 interface Handler {
        /**
         * List handled types
-        * @return array
+        * @return string[]
         */
        function types() : array;
 
        /**
         * Decode HTTP message body
-        * @param Body $body
-        * @return mixed
         */
-       function decode(Body $body);
+       function decode(Body $body) : mixed;
 
        /**
         * Encode HTTP message body
-        * @param $data
-        * @return Body
         */
-       function encode($data) : Body;
+       function encode(mixed $data) : Body;
 }
index 979c97d055fe8e11dc83f67f5ad56bee40cc82b9..342719d227cb0942b4d5d76e11eafd9b0d5e9e6b 100644 (file)
@@ -20,7 +20,7 @@ final class Base64 implements Handler {
         * @inheritdoc
         * @param string $data
         */
-       function encode($data): Body {
+       function encode(mixed $data): Body {
                if (!is_scalar($data)) {
                        throw new InvalidArgumentException(
                                "BASE64 encoding argument must be scalar, got ".typeof($data));
@@ -32,7 +32,7 @@ final class Base64 implements Handler {
         * @inheritdoc
         * @return string
         */
-       function decode(Body $body) {
+       function decode(Body $body) : string {
                $data = base64_decode($body, true);
 
                if (false === $data) {
index d5b6a5847754246bf6591fd156e1df6f95f4630d..008e7e6ad3ee40c3b47bb749eece83f91d43720c 100644 (file)
@@ -9,11 +9,6 @@ use seekat\Exception\UnexpectedValueException;
 use function seekat\typeof;
 
 final class Json implements Handler {
-       /**
-        * @var int
-        */
-       private $flags;
-
        /**
         * @inheritdoc
         */
@@ -24,14 +19,13 @@ final class Json implements Handler {
        /**
         * @param int $flags json_encode() flags
         */
-       function __construct(int $flags = 0) {
-               $this->flags = $flags;
+       function __construct(private readonly int $flags = 0) {
        }
 
        /**
         * @inheritdoc
         */
-       function encode($data): Body {
+       function encode(mixed $data): Body {
                if (is_scalar($data)) {
                        $json = $data;
                } else {
@@ -49,7 +43,7 @@ final class Json implements Handler {
        /**
         * @inheritdoc
         */
-       function decode(Body $body) {
+       function decode(Body $body) : mixed {
                $data = json_decode($body);
                if (!isset($data) && json_last_error()) {
                        throw new UnexpectedValueException("Could not decode JSON: ".
index 6a8535ee7749bd50f7dfbbc5e39aab86fdf411f7..3ab587d3feb95a08258a77e7662a97f1e6ccde27 100644 (file)
@@ -17,7 +17,7 @@ final class Stream implements Handler {
         * @inheritdoc
         * @param resource $data
         */
-       function encode($data): Body {
+       function encode(mixed $data): Body {
                return new Body($data);
        }
 
@@ -25,7 +25,7 @@ final class Stream implements Handler {
         * @inheritdoc
         * @return resource
         */
-       function decode(Body $body) {
+       function decode(Body $body) : mixed {
                return $body->getResource();
        }
 }
index 25e6e805875f1abed6ff3cd5d0834ab8ba3b61f2..1f13a61bd7d0d9ba7ae0adcea2d63a0915d0c808 100644 (file)
@@ -17,21 +17,20 @@ final class Text implements Handler {
 
        /**
         * @inheritdoc
-        * @param string $data
         */
-       function encode($data): Body {
+       function encode(mixed $data): Body {
                if (isset($data) && !is_scalar($data)) {
                        throw new InvalidArgumentException(
                                "Text encoding argument must be scalar, got ".typeof($data));
                }
-               return (new Body)->append($data);
+               return (new Body)->append((string) $data);
        }
 
        /**
         * @inheritdoc
         * @return string
         */
-       function decode(Body $body) {
+       function decode(Body $body) : string {
                return (string) $body;
        }
 }
index e0d36b72ad44c6bd1d50317576980bf781379bd8..1ef0b1d38ae1323a4165c1d2f5409f1442863645 100644 (file)
@@ -5,54 +5,52 @@ namespace seekat\API;
 interface Future {
        /**
         * @param callable $onCancel
-        * @return mixed Promisor providing a promise() method
+        * @return object Promisor providing a promise() method
         */
-       function createContext(callable $onCancel = null);
+       function createContext(callable $onCancel = null) : object;
 
        /**
-        * @param object $context Promisor
-        * @return mixed promise
+        * @return object promise
         */
-       function getPromise($context);
+       function getPromise(object $context) : object;
+
+       function isPromise(object $promise) : bool;
+
+       function cancelPromise(object $promise) : void;
 
        /**
-        * @param mixed $promise
-        * @return bool
+        * @return object promise
         */
-       function isPromise($promise) : bool;
+       function handlePromise(object $promise, callable $onResult = null, callable $onError = null) : object;
 
        /**
-        * @param mixed $promise
-        * @return bool
+        * Create an immediately resolved promise
         */
-       function cancelPromise($promise);
+       function resolve(mixed $value) : object;
 
        /**
-        * @param mixed $promise
-        * @param callable|null $onResult
-        * @param callable|null $onError
-        * @return mixed promise
+        * @param object $context Promisor returned by createContext
         */
-       function handlePromise($promise, callable $onResult = null, callable $onError = null);
+       function resolver(object $context) : \Closure;
 
        /**
-        * @param object $context Promisor returned by createContext
-        * @param mixed $value
-        * @return void
+        * Create an immediately rejected promise
         */
-       function resolve($context, $value);
+       function reject(mixed $reason) : object;
 
        /**
         * @param object $context Promisor returned by createContext
-        * @param mixed $reason
-        * @return void
         */
-       function reject($context, $reason);
+       function rejecter(object $context) : \Closure;
 
        /**
-        * @param object $context Promisor returned by createContext
         * @param array $promises
-        * @return mixed promise
+        * @return object promise
+        */
+       function all(array $promises) : object;
+
+       /**
+        *
         */
-       function all($context, array $promises);
+       function reducer() : \Closure;
 }
diff --git a/lib/API/Future/Amp2.php b/lib/API/Future/Amp2.php
new file mode 100644 (file)
index 0000000..51eb8c6
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+
+namespace seekat\API\Future;
+
+use Amp;
+use seekat\API\Future;
+use function seekat\Exception\exception;
+
+final class Amp2 extends Common implements Future {
+       protected string $promiseType = Amp\Promise::class;
+
+       function createContext(callable $onCancel = null) : Amp\Deferred {
+               $context = new Amp\Deferred();
+               if (isset($onCancel)) {
+                       $this->cancellations[$context->promise()] = $onCancel;
+               }
+               return $context;
+       }
+
+       function handlePromise(object $promise, callable $onResult = null, callable $onError = null) : Amp\Promise {
+               $promise->onResolve(function($error = null, $result = null) use($onResult, $onError) {
+                       if ($error) {
+                               if ($onError) {
+                                       $onError($error);
+                               }
+                       } else {
+                               if ($onResult) {
+                                       $onResult($result);
+                               }
+                       }
+               });
+               return $promise;
+       }
+
+       function reject(mixed $reason) : object {
+               $this->createContext()->fail(\seekat\Exception\exception($reason));
+       }
+
+       function rejecter(object $context) : \Closure {
+               return function($reason) use($context) {
+                       $context->fail(exception($reason));
+               };
+       }
+
+       /**
+        * @param array<Amp\Promise> $promises
+        */
+       function all(array $promises) : Amp\Promise {
+               return Amp\Promise\all($promises);
+       }
+}
diff --git a/lib/API/Future/Common.php b/lib/API/Future/Common.php
new file mode 100644 (file)
index 0000000..afbc62e
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+
+namespace seekat\API\Future;
+
+use seekat\API\Future;
+use seekat\Exception\UnexpectedValueException;
+
+abstract class Common implements Future {
+       protected \WeakMap $cancellations;
+       protected string $promiseType;
+
+       public function __construct() {
+               if (empty($this->promiseType)) {
+                       throw new UnexpectedValueException("Promise type must be set in Future implementation");
+               }
+               $this->cancellations = new \WeakMap;
+       }
+
+       function isPromise(object $promise): bool {
+               return $promise instanceof $this->promiseType;
+       }
+
+       function getPromise(object $context) : object {
+               return $context->promise();
+       }
+
+       function cancelPromise(object $promise) : void {
+               if (isset($this->cancellations[$promise])) {
+                       $this->cancellations[$promise]();
+               }
+       }
+
+       function resolve(mixed $value) : object {
+               $context = $this->createContext();
+               $promise = $context->promise();
+               $context->resolve($value);
+               return $promise;
+       }
+
+       function resolver(object $context) : \Closure {
+               return function($value) use($context) {
+                       $context->resolve($value);
+               };
+       }
+
+       function reducer() : \Closure {
+               return function(array $promises) {
+                       return $this->all($promises);
+               };
+       }
+
+}
diff --git a/lib/API/Future/React2.php b/lib/API/Future/React2.php
new file mode 100644 (file)
index 0000000..6cd27a3
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+
+namespace seekat\API\Future;
+
+use seekat\API\Future;
+use React;
+
+final class React2 extends Common implements Future {
+       protected string $promiseType = React\Promise\Promise::class;
+
+       function createContext(callable $onCancel = null) : React\Promise\PromisorInterface {
+               $context = new React\Promise\Deferred($onCancel);
+               if (isset($onCancel)) {
+                       $this->cancellations[$context->promise()] = $context->promise()->cancel(...);
+               }
+               return $context;
+       }
+
+       function handlePromise(object $promise, callable $onResult = null, callable $onError = null) : React\Promise\PromiseInterface {
+               return $promise->then($onResult, $onError);
+       }
+
+       function reject(mixed $reason) : object {
+               $context = $this->createContext();
+               $context->reject($reason);
+               return $context->promise();
+       }
+
+       function rejecter(object $context) : \Closure {
+               return function($reason) use($context) {
+                       $context->reject($reason);
+               };
+       }
+
+       /**
+        * @param array<React\Promise\PromiseInterface> $promises
+        * @return React\Promise\PromiseInterface
+        */
+       function all(array $promises) : React\Promise\PromiseInterface {
+               return React\Promise\all($promises);
+       }
+}
index 3cddb221b06c1188713a7e9065cc9f3b7bed397d..d2a92329133eca4acc56bc61c52b4ad2dbc9fdee 100644 (file)
 
 namespace seekat\API\Future;
 
-use Amp\Deferred as AmpDeferred;
-use Amp\Promise as AmpPromise;
-use React\Promise\Deferred as ReactDeferred;
-use React\Promise\PromiseInterface as ReactPromise;
 use seekat\API\Future;
 
-/**
- * @param Future $future
- * @param mixed $value
- * @return mixed promise
- */
-function resolve(Future $future, $value) {
-       $promisor = $future->createContext();
-       $future->resolve($promisor, $value);
-       return $future->getPromise($promisor);
+function react() : React2 {
+       return new React2;
 }
 
-/**
- * @param Future $future
- * @param mixed $reason
- * @return mixed promise
- */
-function reject(Future $future, $reason) {
-       $promisor = $future->createContext();
-       $future->reject($promisor, $reason);
-       return $future->getPromise($promisor);
+function amp() : Amp2 {
+       return new Amp2;
 }
 
-/**
- * @param Future $future
- * @param mixed $context Promisor
- * @return \Closure
- */
-function resolver(Future $future, $context) {
-       return function($value) use($future, $context) {
-               $future->resolve($context, $value);
-       };
-}
-
-/**
- * @param Future $future
- * @param mixed $context Promisor
- * @return \Closure
- */
-function rejecter(Future $future, $context) {
-       return function($reason) use($future, $context) {
-               $future->reject($context, $reason);
-       };
-}
-
-/**
- * @param Future $future
- * @param mixed $context Promisor
- * @return \Closure
- */
-function reducer(Future $future, $context) {
-       return function(array $promises) use($future, $context) {
-               return $future->all($context, $promises);
-       };
-}
-
-/**
- * @return Future
- */
-function react() {
-       return new class implements Future {
-               /**
-                * @param callable|null $onCancel
-                * @return ReactDeferred
-                */
-               function createContext(callable $onCancel = null) {
-                       return new ReactDeferred($onCancel);
-               }
-
-               function getPromise($context) {
-                       /* @var $context ReactDeferred */
-                       return $context->promise();
-               }
-
-               function isPromise($promise) : bool {
-                       return $promise instanceof ReactPromise;
-               }
-
-               function handlePromise($promise, callable $onResult = null, callable $onError = null) {
-                       return $promise->then($onResult, $onError);
-               }
-
-               function cancelPromise($promise) {
-                       /* @var $promise \React\Promise\Promise */
-                       $promise->cancel();
-               }
-
-               function resolve($context, $value) {
-                       /* @var $context ReactDeferred */
-                       $context->resolve($value);
-               }
-
-               function reject($context, $reason) {
-                       /* @var $context ReactDeferred */
-                       $context->reject($reason);
-               }
-
-               function all($context, array $promises) {
-                       return \React\Promise\all($promises);
-               }
-       };
-}
-
-/**
- * @return Future
- */
-function amp() {
-       return new class implements Future {
-               /**
-                * @return AmpDeferred
-                */
-               function createContext(callable $onCancel = null) {
-                       $context = new AmpDeferred();
-                       /** @noinspection PhpUndefinedFieldInspection */
-                       $context->promise()->cancel = function() use($onCancel, $context) {
-                               $onCancel();
-                       };
-                       return $context;
-               }
-
-               function getPromise($context) {
-                       /* @var $context AmpDeferred */
-                       return $context->promise();
-               }
-
-               function isPromise($promise) : bool {
-                       return $promise instanceof AmpPromise;
-               }
-
-               function handlePromise($promise, callable $onResult = null, callable $onError = null) {
-                       $promise->onResolve(function($error = null, $result = null) use($onResult, $onError) {
-                               if ($error) {
-                                       if ($onError) {
-                                               $onError($error);
-                                       }
-                               } else {
-                                       if ($onResult) {
-                                               $onResult($result);
-                                       }
-                               }
-                       });
-                       return $promise;
-               }
-
-               function cancelPromise($promise) {
-                       /** @var $promise AmpPromise */
-                       /** @noinspection PhpUndefinedFieldInspection */
-                       ($promise->cancel)();
-               }
-
-               function resolve($context, $value) {
-                       /* @var $context AmpDeferred */
-                       $context->resolve($value);
-               }
-
-               function reject($context, $reason) {
-                       /* @var $context AmpDeferred */
-                       $context->fail(\seekat\Exception\exception($reason));
-               }
-
-               function all($context, array $promises) {
-                       return \Amp\Promise\all($promises);
-               }
-       };
+function any() : Amp2|React2 {
+       if (interface_exists(\Amp\Promise::class, true)) {
+               return amp();
+       }
+       if (interface_exists(\React\Promise\PromiseInterface::class, true)) {
+               return react();
+       }
+       throw new \Exception("Cannot find any promise implementation");
 }
diff --git a/lib/API/Iterator.php b/lib/API/Iterator.php
deleted file mode 100644 (file)
index b218747..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-
-namespace seekat\API;
-
-use http\Url;
-use Iterator as BaseIterator;
-use seekat\API;
-
-class Iterator implements BaseIterator
-{
-       /**
-        * The endpoint
-        * @var API
-        */
-       private $api;
-
-       /**
-        * The iterator's data
-        * @var array
-        */
-       private $data;
-
-       /**
-        * The current key
-        * @var int|string
-        */
-       private $key;
-
-       /**
-        * The current data entry
-        * @var mixed
-        */
-       private $cur;
-
-       /**
-        * Create a new iterator over $data returning \seekat\API instances
-        *
-        * @var API $api The endpoint
-        * @var array|object $data
-        */
-       function __construct(API $api) {
-               $this->api = $api;
-               $this->data = (array) $api->export()["data"];
-       }
-
-       /**
-        * Get the current key
-        *
-        * @return int|string
-        */
-       function key() {
-               return $this->key;
-       }
-
-       /**
-        * Get the current data entry
-        *
-        * @return API
-        */
-       function current() {
-               return $this->cur;
-       }
-
-       function next() {
-               if (list($key, $cur) = each($this->data)) {
-                       $this->key = $key;
-                       if ($this->api->$key->exists("url", $url)) {
-                               $url = new Url($url);
-                               $this->cur = $this->api->withUrl($url)->withData($cur);
-                       } else {
-                               $this->cur = $this->api->$key->withData($cur);
-                       }
-               } else {
-                       $this->key = null;
-                       $this->cur = null;
-               }
-       }
-
-       function valid() {
-               return isset($this->cur);
-       }
-
-       function rewind() {
-               if (is_array($this->data)) {
-                       reset($this->data);
-                       $this->next();
-               }
-       }
-}
index 20fbc6d846ec3226beb3ee518ade5e6161da69e3..9f4f976570de3d5ed9e39f429ef2751eac7c0d11 100644 (file)
@@ -4,25 +4,18 @@ namespace seekat\API;
 
 use http\{Header, Params, QueryString, Url};
 use seekat\Exception\UnexpectedValueException;
-use Serializable;
 
-final class Links implements Serializable {
+final class Links {
        /**
         * Parsed "Link" relations
-        * @var Params
-        */
-       private $params;
-
-       /**
-        * Parsed "Link" relations
-        * @var array
+        * @var array<string, Url>
         */
        private $relations = [];
 
        /**
         * Parse the hypermedia link header
         *
-        * @param Header $links The Link header
+        * @param ?Header $links The Link header
         * @throws UnexpectedValueException
         */
        function __construct(Header $links = null) {
@@ -30,33 +23,12 @@ final class Links implements Serializable {
                        if (strcasecmp($links->name, "Link")) {
                                throw new UnexpectedValueException("Expected 'Link' header, got: '{$links->name}'");
                        }
-                       $this->unserialize($links->value);
-               }
-       }
-
-       /**
-        * @return string
-        */
-       function __toString() : string {
-               return $this->serialize();
-       }
-
-       /**
-        * @return string
-        */
-       function serialize() {
-               return (string) $this->params;
-       }
-
-       /**
-        * @param string $links
-        */
-       function unserialize($links) {
-               $this->params = new Params($links, ",", ";", "=",
-                       Params::PARSE_RFC5988 | Params::PARSE_ESCAPED);
-               if ($this->params->params) {
-                       foreach ($this->params->params as $link => $param) {
-                               $this->relations[$param["arguments"]["rel"]] = new Url($link);
+                       $params = new Params($links->value, ",", ";", "=",
+                               Params::PARSE_RFC5988 | Params::PARSE_ESCAPED);
+                       if ($params->params) {
+                               foreach ($params->params as $link => $param) {
+                                       $this->relations[$param["arguments"]["rel"]] = new Url($link);
+                               }
                        }
                }
        }
@@ -64,7 +36,7 @@ final class Links implements Serializable {
        /**
         * Receive the link header's parsed relations
         *
-        * @return array
+        * @return array<string, Url>
         */
        function getRelations() : array {
                return $this->relations;
@@ -74,10 +46,8 @@ final class Links implements Serializable {
         * Get the URL of the link's "next" relation
         *
         * Returns the link's "last" relation if it exists and "next" is not set.
-        *
-        * @return Url
         */
-       function getNext() {
+       function getNext() : ?Url {
                if (isset($this->relations["next"])) {
                        return $this->relations["next"];
                }
@@ -91,10 +61,8 @@ final class Links implements Serializable {
         * Get the URL of the link's "prev" relation
         *
         * Returns the link's "first" relation if it exists and "prev" is not set.
-        *
-        * @return Url
         */
-       function getPrev() {
+       function getPrev() : ?Url {
                if (isset($this->relations["prev"])) {
                        return $this->relations["prev"];
                }
@@ -106,10 +74,8 @@ final class Links implements Serializable {
 
        /**
         * Get the URL of the link's "last" relation
-        *
-        * @return Url
         */
-       function getLast() {
+       function getLast() : ?Url {
                if (isset($this->relations["last"])) {
                        return $this->relations["last"];
                }
@@ -118,10 +84,8 @@ final class Links implements Serializable {
 
        /**
         * Get the URL of the link's "first" relation
-        *
-        * @return Url
         */
-       function getFirst() {
+       function getFirst() : ?Url {
                if (isset($this->relations["first"])) {
                        return $this->relations["first"];
                }
@@ -134,7 +98,7 @@ final class Links implements Serializable {
         * @param string $which The relation of which to extract the page
         * @return int The current page sequence
         */
-       function getPage($which) {
+       function getPage($which) : int {
                if (($link = $this->{"get$which"}())) {
                        $url = new Url($link, null, 0);
                        $qry = new QueryString($url->query);
index 8b3d4e555406e0600b9dd912be7faa44f0db22ff..f3791258e7f68924f54b5325685b915b9d51967c 100644 (file)
@@ -11,12 +11,11 @@ use seekat\API\Future;
  *
  * @return mixed promise
  */
-function first(API $api, Cache\Service $cache = null) {
-       $links = $api->getLinks();
-       if ($links && ($first = $links->getFirst())) {
-               return $api->withUrl($first)->get(null, null, $cache);
+function first(API $api) {
+       if (($first = $api->getLinks()?->getFirst())) {
+               return $api->withUrl($first)->get();
        }
-       return Future\resolve($api->getFuture(), null);
+       return $api->getFuture()->resolve(null);
 }
 
 /**
@@ -24,12 +23,11 @@ function first(API $api, Cache\Service $cache = null) {
  *
  * @return mixed promise
  */
-function prev(API $api, Cache\Service $cache = null) {
-       $links = $api->getLinks();
-       if ($links && ($prev = $links->getPrev())) {
-               return $api->withUrl($prev)->get(null, null, $cache);
+function prev(API $api) {
+       if (($prev = $api->getLinks()?->getPrev())) {
+               return $api->withUrl($prev)->get();
        }
-       return Future\resolve($api->getFuture(), null);
+       return $api->getFuture()->resolve(null);
 }
 
 /**
@@ -37,12 +35,11 @@ function prev(API $api, Cache\Service $cache = null) {
  *
  * @return mixed promise
  */
-function next(API $api, Cache\Service $cache = null) {
-       $links = $api->getLinks();
-       if ($links && ($next = $links->getNext())) {
-               return $api->withUrl($next)->get(null, null, $cache);
+function next(API $api) {
+       if (($next = $api->getLinks()?->getNext())) {
+               return $api->withUrl($next)->get();
        }
-       return Future\resolve($api->getFuture(), null);
+       return $api->getFuture()->resolve(null);
 }
 
 /**
@@ -55,6 +52,6 @@ function last(API $api, Cache\Service $cache = null) {
        if ($links && ($last = $links->getLast())) {
                return $api->withUrl($last)->get(null, null, $cache);
        }
-       return Future\resolve($api->getFuture(), null);
+       return $api->getFuture()->resolve(null);
 }
 
index 0c7171a0176886845395e0c8056256317e8af36d..1930ad091713419d28ed3766328c83a1cdf9caf7 100644 (file)
@@ -2,12 +2,14 @@
 
 namespace seekat\Exception;
 
+use Throwable;
+
 /**
- * @param string|\Throwable $message
- * @return \Throwable
+ * @param string|Throwable $message
+ * @return Throwable
  */
-function exception(&$message) : \Throwable {
-       if ($message instanceof \Throwable){
+function exception(&$message) : Throwable {
+       if ($message instanceof Throwable){
                $exception = $message;
                $message = $exception->getMessage();
        } else {
@@ -18,11 +20,10 @@ function exception(&$message) : \Throwable {
 
 /**
  * Canonical error message from a string or Exception
- * @param string|\Throwable $error
- * @return string
+ * @param string|Throwable $error
  */
 function message(&$error) : ?string {
-       if ($error instanceof \Throwable) {
+       if ($error instanceof Throwable) {
                $message = $error->getMessage();
        } else {
                $message = $error;
index 9130fd40b53074d1cc46cf97605acde67e4a6b65..8a1615be160d1cf9b9bc3037056b1296e120601e 100644 (file)
@@ -11,12 +11,12 @@ namespace {
 
 namespace seekat {
        /**
-        * Generate a human readable representation of a variable
+        * Generate a human-readable representation of a variable
         * @param mixed $arg
         * @param bool $export whether to var_export the $arg
         * @return string
         */
-       function typeof($arg, $export = false) {
+       function typeof($arg, bool $export = false) : string {
                $type = is_object($arg)
                        ? "instance of ".get_class($arg)
                        : gettype($arg);
index ddf7f545c59340c26363ec915fbcfe05208b0a1c..62632b433ec1c335c69e338c8cbbceff75da1223 100644 (file)
@@ -5,30 +5,22 @@ class CacheTest extends BaseTest
        use ConsumePromise;
        use AssertSuccess;
 
-       /**
-        * @var seekat\API\Call\Cache\Service
-        */
-       private $cache;
-
-       function setUp() : void {
-               $this->cache = new seekat\API\Call\Cache\Service\Hollow;
-       }
-
        /**
         * @group testdox
         * @dataProvider provideAPI
         */
        function testCachesSuccessiveCalls($api) {
-               $m6w6 = $this->assertSuccess($api->users->m6w6, null, null, $this->cache);
-               $data = $this->cache->getStorage();
-               $m6w6_ = $this->assertSuccess($api->users->m6w6, null, null, $this->cache);
+               $api->getCache()->clear();
+               $m6w6 = $this->assertSuccess($api->users->m6w6);
+               $data = $api->getCache()->getStorage();
+               $m6w6_ = $this->assertSuccess($api->users->m6w6);
 
                $this->assertEquals("m6w6", $m6w6->login);
                $this->assertEquals("m6w6", $m6w6_->login);
 
                $this->assertIsArray($data);
                $this->assertCount(1, $data);
-               $this->assertEquals($data, $this->cache->getStorage());
+               $this->assertEquals($data, $api->getCache()->getStorage());
        }
 
        /**
@@ -36,6 +28,25 @@ class CacheTest extends BaseTest
         * @dataProvider provideAPI
         */
        function testRefreshesStaleCacheEntries($api) {
-               $this->markTestIncomplete("TODO");
+               $api->getCache()->clear();
+               $m6w6 = $this->assertSuccess($api->users->m6w6);
+
+               $data = $api->getCache()->getStorage();
+               /* @var \http\Header $resp */
+               $resp = current($data);
+               $resp->setHeader("X-Cache-Time", null);
+               $resp->setHeader("Cache-Control", null);
+               $resp->setHeader("Expires", 0);
+
+               $m6w6_ = $this->assertSuccess($api->users->m6w6);
+
+               $this->assertEquals("m6w6", $m6w6->login);
+               $this->assertEquals("m6w6", $m6w6_->login);
+
+               $this->assertIsArray($data);
+               $this->assertCount(1, $data);
+               $this->assertEquals($data, $api->getCache()->getStorage());
+
+               $this->assertIsNumeric($resp->getHeader("X-Cache-Time"));
        }
 }
index 3945245d0ff50af33fc62e9c7460d5caacc52317..df6e8fae11ce86d344f12e0ae32d04e06103da0f 100644 (file)
@@ -48,7 +48,7 @@ class ContentTypeTest extends BaseTest
                        function encode($data): Body {
                                return new Body;
                        }
-                       function decode(Body $body) {
+                       function decode(Body $body) : string {
                                return (string) $body;
                        }
                });
index e7d7afb621ef9958e7043184e07caf4d164bdd24..4b04a942f8a009481c784ad57d00bfc79e837491 100644 (file)
@@ -44,15 +44,12 @@ function logger() : \Monolog\Logger {
 class BaseTest extends \PHPUnit\Framework\TestCase
 {
        function provideAPI() {
-               $auth = \seekat\API\auth("token", getenv("GITHUB_TOKEN"));
                $headers = headers();
-               $url = null;
-               $client = null;
                $logger = logger();
 
                return [
-                       "using ReactPHP" => [new \seekat\API(\seekat\API\Future\react(), $headers, $url, $client, $logger)],
-                       "using AmPHP"   => [new \seekat\API(\seekat\API\Future\amp(), $headers, $url, $client, $logger)],
+                       "using ReactPHP" => [new \seekat\API(\seekat\API\Future\react(), $headers, logger: $logger)],
+                       "using AmPHP"   => [new \seekat\API(\seekat\API\Future\amp(), $headers, logger: $logger)],
                ];
        }
 }