1===============
2Client Handlers
3===============
4
5Client handlers accept a request array and return a future response array that
6can be used synchronously as an array or asynchronously using a promise.
7
8Built-In Handlers
9-----------------
10
11RingPHP comes with three built-in client handlers.
12
13Stream Handler
14~~~~~~~~~~~~~~
15
16The ``GuzzleHttp\Ring\Client\StreamHandler`` uses PHP's
17`http stream wrapper <http://php.net/manual/en/wrappers.http.php>`_ to send
18requests.
19
20.. note::
21
22    This handler cannot send requests concurrently.
23
24You can provide an associative array of custom stream context options to the
25StreamHandler using the ``stream_context`` key of the ``client`` request
26option.
27
28.. code-block:: php
29
30    use GuzzleHttp\Ring\Client\StreamHandler;
31
32    $response = $handler([
33        'http_method' => 'GET',
34        'uri' => '/',
35        'headers' => ['host' => ['httpbin.org']],
36        'client' => [
37            'stream_context' => [
38                'http' => [
39                    'request_fulluri' => true,
40                    'method' => 'HEAD'
41                ],
42                'socket' => [
43                    'bindto' => '127.0.0.1:0'
44                ],
45                'ssl' => [
46                    'verify_peer' => false
47                ]
48            ]
49        ]
50    ]);
51
52    // Even though it's already completed, you can still use a promise
53    $response->then(function ($response) {
54        echo $response['status']; // 200
55    });
56
57    // Or access the response using the future interface
58    echo $response['status']; // 200
59
60cURL Handler
61~~~~~~~~~~~~
62
63The ``GuzzleHttp\Ring\Client\CurlHandler`` can be used with PHP 5.5+ to send
64requests using cURL easy handles. This handler is great for sending requests
65one at a time because the execute and select loop is implemented in C code
66which executes faster and consumes less memory than using PHP's
67``curl_multi_*`` interface.
68
69.. note::
70
71    This handler cannot send requests concurrently.
72
73When using the CurlHandler, custom curl options can be specified as an
74associative array of `cURL option constants <http://php.net/manual/en/curl.constants.php>`_
75mapping to values in the ``client`` option of a requst using the **curl** key.
76
77.. code-block:: php
78
79    use GuzzleHttp\Ring\Client\CurlHandler;
80
81    $handler = new CurlHandler();
82
83    $request = [
84        'http_method' => 'GET',
85        'headers'     => ['host' => [Server::$host]],
86        'client'      => ['curl' => [CURLOPT_LOW_SPEED_LIMIT => 10]]
87    ];
88
89    $response = $handler($request);
90
91    // The response can be used directly as an array.
92    echo $response['status']; // 200
93
94    // Or, it can be used as a promise (that has already fulfilled).
95    $response->then(function ($response) {
96        echo $response['status']; // 200
97    });
98
99cURL Multi Handler
100~~~~~~~~~~~~~~~~~~
101
102The ``GuzzleHttp\Ring\Client\CurlMultiHandler`` transfers requests using
103cURL's `multi API <http://curl.haxx.se/libcurl/c/libcurl-multi.html>`_. The
104``CurlMultiHandler`` is great for sending requests concurrently.
105
106.. code-block:: php
107
108    use GuzzleHttp\Ring\Client\CurlMultiHandler;
109
110    $handler = new CurlMultiHandler();
111
112    $request = [
113        'http_method' => 'GET',
114        'headers'     => ['host' => [Server::$host]]
115    ];
116
117    // this call returns a future array immediately.
118    $response = $handler($request);
119
120    // Ideally, you should use the promise API to not block.
121    $response
122        ->then(function ($response) {
123            // Got the response at some point in the future
124            echo $response['status']; // 200
125            // Don't break the chain
126            return $response;
127        })->then(function ($response) {
128            // ...
129        });
130
131    // If you really need to block, then you can use the response as an
132    // associative array. This will block until it has completed.
133    echo $response['status']; // 200
134
135Just like the ``CurlHandler``, the ``CurlMultiHandler`` accepts custom curl
136option in the ``curl`` key of the ``client`` request option.
137
138Mock Handler
139~~~~~~~~~~~~
140
141The ``GuzzleHttp\Ring\Client\MockHandler`` is used to return mock responses.
142When constructed, the handler can be configured to return the same response
143array over and over, a future response, or a the evaluation of a callback
144function.
145
146.. code-block:: php
147
148    use GuzzleHttp\Ring\Client\MockHandler;
149
150    // Return a canned response.
151    $mock = new MockHandler(['status' => 200]);
152    $response = $mock([]);
153    assert(200 == $response['status']);
154    assert([] == $response['headers']);
155
156Implementing Handlers
157---------------------
158
159Client handlers are just PHP callables (functions or classes that have the
160``__invoke`` magic method). The callable accepts a request array and MUST
161return an instance of ``GuzzleHttp\Ring\Future\FutureArrayInterface`` so that
162the response can be used by both blocking and non-blocking consumers.
163
164Handlers need to follow a few simple rules:
165
1661. Do not throw exceptions. If an error is encountered, return an array that
167   contains the ``error`` key that maps to an ``\Exception`` value.
1682. If the request has a ``delay`` client option, then the handler should only
169   send the request after the specified delay time in seconds. Blocking
170   handlers may find it convenient to just let the
171   ``GuzzleHttp\Ring\Core::doSleep($request)`` function handle this for them.
1723. Always return an instance of ``GuzzleHttp\Ring\Future\FutureArrayInterface``.
1734. Complete any outstanding requests when the handler is destructed.
174