Client   F
last analyzed

Complexity

Total Complexity 92

Size/Duplication

Total Lines 646
Duplicated Lines 4.64 %

Coupling/Cohesion

Components 2
Dependencies 12

Test Coverage

Coverage 94.03%

Importance

Changes 0
Metric Value
wmc 92
c 0
b 0
f 0
lcom 2
cbo 12
dl 30
loc 646
ccs 189
cts 201
cp 0.9403
rs 3.7879

28 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A sendAsync() 0 6 1
A setAuth() 0 6 1
A setHeadersToSign() 0 6 1
A setMaxBodySize() 0 6 1
A setTimeout() 0 6 1
A setInstanceVerbose() 0 6 1
A setInstanceDebug() 0 6 1
A setSimpleLog() 0 12 3
A requestAsync() 0 12 2
A setHost() 0 17 3
A setLogger() 0 20 2
A createInstance() 10 10 2
A createFromEnv() 10 10 2
A createFromEdgeRcFile() 10 10 2
A setDebug() 0 4 1
A setVerbose() 0 4 1
B getDebugOption() 0 14 9
B isDebug() 0 12 7
B isVerbose() 0 12 7
A setAuthentication() 0 15 4
A setAuthenticationHandler() 0 20 4
A setBasicOptions() 0 12 4
A setConfigOption() 0 10 1
C setDebugHandler() 0 35 8
A setLogHandler() 0 14 3
D setVerboseHandler() 0 37 10
D setRequestOptions() 0 32 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Client often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Client, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Akamai {OPEN} EdgeGrid Auth Client
4
 *
5
 * @author Davey Shafik <[email protected]>
6
 * @copyright Copyright 2016 Akamai Technologies, Inc. All rights reserved.
7
 * @license Apache 2.0
8
 * @link https://github.com/akamai-open/AkamaiOPEN-edgegrid-php-client
9
 * @link https://developer.akamai.com
10
 * @link https://developer.akamai.com/introduction/Client_Auth.html
11
 */
12
namespace Akamai\Open\EdgeGrid;
13
14
use Akamai\Open\EdgeGrid\Handler\Authentication as AuthenticationHandler;
15
use Akamai\Open\EdgeGrid\Handler\Debug as DebugHandler;
16
use Akamai\Open\EdgeGrid\Handler\Verbose as VerboseHandler;
17
18
/**
19
 * Akamai {OPEN} EdgeGrid Client for PHP
20
 *
21
 * Akamai\Open\EdgeGrid\Client wraps GuzzleHttp\Client
22
 * providing request authentication/signing for Akamai
23
 * {OPEN} APIs.
24
 *
25
 * This client works _identically_ to GuzzleHttp\Client
26
 *
27
 * However, if you try to call an Akamai {OPEN} API you *must*
28
 * first call {@see Akamai\Open\EdgeGrid\Client->setAuth()}.
29
 *
30
 * @package Akamai\Open\EdgeGrid\Client
31
 */
32
class Client extends \GuzzleHttp\Client implements \Psr\Log\LoggerAwareInterface
33
{
34
    const VERSION = '1.0.0';
35
36
    /**
37
     * @const int Default Timeout in seconds
38
     */
39
    const DEFAULT_REQUEST_TIMEOUT = 300;
40
41
    /**
42
     * @var bool|array|resource Whether verbose mode is enabled
43
     *
44
     * - true - Use STDERR
45
     * - array - output/error streams (different)
46
     * - resource - output/error stream (same)
47
     */
48
    protected static $staticVerbose = false;
49
50
    /**
51
     * @var bool|resource Whether debug mode is enabled
52
     */
53
    protected static $staticDebug = false;
54
55
    /**
56
     * @var \Akamai\Open\EdgeGrid\Authentication
57
     */
58
    protected $authentication;
59
60
    /**
61
     * @var \Akamai\Open\EdgeGrid\Handler\Verbose
62
     */
63
    protected $verboseHandler;
64
65
    /**
66
     * @var \Akamai\Open\EdgeGrid\Handler\Debug
67
     */
68
    protected $debugHandler;
69
70
    /**
71
     * @var bool|array|resource Whether verbose mode is enabled
72
     *
73
     * - true - Use STDOUT
74
     * - array - output/error streams (different)
75
     * - resource - output/error stream (same)
76
     */
77
    protected $verbose = false;
78
79
    /**
80
     * @var bool|resource Whether debugging is enabled
81
     */
82
    protected $debug = false;
83
84
    /**
85
     * @var bool Whether to override the static verbose setting
86
     */
87
    protected $verboseOverride = false;
88
89
    /**
90
     * @var bool Whether to override the static debug setting
91
     */
92
    protected $debugOverride = false;
93
94
    /**
95
     * @var callable Logging Handler
96
     */
97
    protected $logger;
98
99
    /**
100
     * \GuzzleHttp\Client-compatible constructor
101
     *
102
     * @param array $config Config options array
103
     * @param Authentication|null $authentication
104
     */
105 131
    public function __construct(
106
        $config = [],
107
        Authentication $authentication = null
108
    ) {
109 131
        $config = $this->setAuthenticationHandler($config, $authentication);
110 131
        $config = $this->setBasicOptions($config);
111 131
        $config['headers']['User-Agent'] = 'Akamai-Open-Edgegrid-PHP/' .
112 131
            self::VERSION . ' ' . \GuzzleHttp\default_user_agent();
113
114 131
        parent::__construct($config);
115 131
    }
116
117
    /**
118
     * Make an Asynchronous request
119
     *
120
     * @param string $method
121
     * @param string $uri
122
     * @param array $options
123
     * @return \GuzzleHttp\Promise\PromiseInterface
124
     * @throws \GuzzleHttp\Exception\GuzzleException
125
     */
126 77
    public function requestAsync($method, $uri = null, array $options = [])
127
    {
128 77
        $options = $this->setRequestOptions($options);
129
130 77
        $query = parse_url($uri, PHP_URL_QUERY);
131 77
        if (!empty($query)) {
132 1
            $uri = substr($uri, 0, (strlen($query)+1) * -1);
133 1
            parse_str($query, $options['query']);
134
        }
135
136 77
        return parent::requestAsync($method, $uri, $options);
137
    }
138
139
    /**
140
     * Send an Asynchronous HTTP request
141
     *
142
     * @param \Psr\Http\Message\RequestInterface $request The HTTP request
143
     * @param array $options Request options
144
     *
145
     * @return \GuzzleHttp\Promise\PromiseInterface
146
     */
147 28
    public function sendAsync(\Psr\Http\Message\RequestInterface $request, array $options = [])
148
    {
149 28
        $options = $this->setRequestOptions($options);
150
151 28
        return parent::sendAsync($request, $options);
152
    }
153
154
    /**
155
     * Set Akamai {OPEN} Authentication Credentials
156
     *
157
     * @param string $client_token
158
     * @param string $client_secret
159
     * @param string $access_token
160
     * @return $this
161
     */
162 60
    public function setAuth($client_token, $client_secret, $access_token)
163
    {
164 60
        $this->authentication->setAuth($client_token, $client_secret, $access_token);
165
166 60
        return $this;
167
    }
168
169
    /**
170
     * Specify the headers to include when signing the request
171
     *
172
     * This is specified by the API, currently no APIs use this
173
     * feature.
174
     *
175
     * @param array $headers
176
     * @return $this
177
     */
178 42
    public function setHeadersToSign(array $headers)
179
    {
180 42
        $this->authentication->setHeadersToSign($headers);
181
182 42
        return $this;
183
    }
184
185
    /**
186
     * Set the max body size
187
     *
188
     * @param int $max_body_size
189
     * @return $this
190
     */
191 42
    public function setMaxBodySize($max_body_size)
192
    {
193 42
        $this->authentication->setMaxBodySize($max_body_size);
194
195 42
        return $this;
196
    }
197
198
    /**
199
     * Set Request Host
200
     *
201
     * @param string $host
202
     * @return $this
203
     */
204 2
    public function setHost($host)
205
    {
206 2
        if (substr($host, -1) === '/') {
207 2
            $host = substr($host, 0, -1);
208
        }
209
210 2
        $headers = $this->getConfig('headers');
211 2
        $headers['Host'] = $host;
212 2
        $this->setConfigOption('headers', $headers);
213
214 2
        if (strpos('/', $host) === false) {
215 2
            $host = 'https://' . $host;
216
        }
217 2
        $this->setConfigOption('base_uri', $host);
218
219 2
        return $this;
220
    }
221
222
    /**
223
     * Set the HTTP request timeout
224
     *
225
     * @param int $timeout_in_seconds
226
     * @return $this
227
     */
228 2
    public function setTimeout($timeout_in_seconds)
229
    {
230 2
        $this->setConfigOption('timeout', $timeout_in_seconds);
231
232 2
        return $this;
233
    }
234
235
    /**
236
     * Print formatted JSON responses to output
237
     *
238
     * @param bool|resource $enable
239
     * @return $this
240
     */
241 4
    public function setInstanceVerbose($enable)
242
    {
243 4
        $this->verboseOverride = true;
244 4
        $this->verbose = $enable;
245 4
        return $this;
246
    }
247
248
    /**
249
     * Print HTTP requests/responses to output
250
     *
251
     * @param bool|resource $enable
252
     * @return $this
253
     */
254 10
    public function setInstanceDebug($enable)
255
    {
256 10
        $this->debugOverride = true;
257 10
        $this->debug = $enable;
258 10
        return $this;
259
    }
260
261
    /**
262
     * Set a PSR-3 compatible logger (or use monolog by default)
263
     *
264
     * @param \Psr\Log\LoggerInterface $logger
265
     * @param string $messageFormat Message format
266
     * @return $this
267
     */
268 24
    public function setLogger(
269
        \Psr\Log\LoggerInterface $logger = null,
270
        $messageFormat = \GuzzleHttp\MessageFormatter::CLF
271
    ) {
272 24
        if ($logger === null) {
273 2
            $handler = new \Monolog\Handler\ErrorLogHandler(\Monolog\Handler\ErrorLogHandler::SAPI);
274 2
            $handler->setFormatter(new \Monolog\Formatter\LineFormatter('%message%'));
275 2
            $logger = new \Monolog\Logger('HTTP Log', [$handler]);
276
        }
277
278 24
        $formatter = new \GuzzleHttp\MessageFormatter($messageFormat);
279
280 24
        $handler = \GuzzleHttp\Middleware::log($logger, $formatter);
281 24
        $this->logger = $handler;
282
283 24
        $handlerStack = $this->getConfig('handler');
284 24
        $this->setLogHandler($handlerStack, $handler);
285
286 24
        return $this;
287
    }
288
289
    /**
290
     * Add logger using a given filename/format
291
     *
292
     * @param string $filename
293
     * @param string $format
294
     * @return \Akamai\Open\EdgeGrid\Client|bool
295
     */
296 4
    public function setSimpleLog($filename, $format = '{code}')
297
    {
298 4
        if ($this->logger && !($this->logger instanceof \Monolog\Logger)) {
299 2
            return false;
300
        }
301
302 2
        $handler = new \Monolog\Handler\StreamHandler($filename);
303 2
        $handler->setFormatter(new \Monolog\Formatter\LineFormatter('%message%'));
304 2
        $log = new \Monolog\Logger('HTTP Log', [$handler]);
305
306 2
        return $this->setLogger($log, $format);
307
    }
308
309 10
    /**
310
     * Create instance using environment (preferred) or .edgerc file (fallback) automatically.
311 10
     *
312
     * @param string $section
313 2
     * @param null $path
314 2
     * @return Client
315
     * @throws \Akamai\Open\EdgeGrid\Authentication\Exception\ConfigException
316
     */
317 2 View Code Duplication
    public static function createInstance($section = 'default', $path = null, array $config = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
318
    {
319
        $auth = \Akamai\Open\EdgeGrid\Authentication::createInstance($section, $path);
320 12
321
        if ($host = $auth->getHost()) {
322 12
            $config['base_uri'] = 'https://' .$host;
323
        }
324 8
325 8
        return new static($config, $auth);
326
    }
327
328 8 View Code Duplication
    public static function createFromEnv($section = 'default', array $config = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
329
    {
330
        $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEnv($section);
331
332
        if ($host = $auth->getHost()) {
333
            $config['base_uri'] = 'https://' . $host;
334
        }
335
336
        return new static($config, $auth);
337
    }
338
339
    /**
340
     * Factory method to create a client using credentials from `.edgerc`
341
     *
342 8
     * Automatically checks your HOME directory, and the current working
343
     * directory for credentials, if no path is supplied.
344 8
     *
345
     * @param string $section Credential section to use
346 8
     * @param string $path Path to .edgerc credentials file
347 8
     * @param array $config Options to pass to the constructor/guzzle
348
     * @return \Akamai\Open\EdgeGrid\Client
349
     */
350 8 View Code Duplication
    public static function createFromEdgeRcFile($section = 'default', $path = null, array $config = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
351
    {
352
        $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile($section, $path);
353
354
        if ($host = $auth->getHost()) {
355
            $config['base_uri'] = 'https://' . $host;
356
        }
357
358 161
        return new static($config, $auth);
359
    }
360 161
361 161
    /**
362
     * Print HTTP requests/responses to STDOUT
363
     *
364
     * @param bool|resource $enable
365
     */
366
    public static function setDebug($enable)
367
    {
368 169
        self::$staticDebug = $enable;
369
    }
370 169
371 169
    /**
372
     * Print formatted JSON responses to STDOUT
373
     *
374
     * @param bool|resource|array $enable
375
     */
376
    public static function setVerbose($enable)
377
    {
378
        self::$staticVerbose = $enable;
379 105
    }
380
381 105
    /**
382 2
     * Handle debug option
383
     *
384
     * @param array $config
385 103
     * @return bool|resource
386 5
     */
387 98
    protected function getDebugOption(array $config)
388 9
    {
389
        if (isset($config['debug'])) {
390
            return ($config['debug'] === true) ? fopen('php://stderr', 'ab') : $config['debug'];
391 89
        }
392
393
        if ($this->debugOverride && $this->debug) {
394
            return ($this->debug === true) ? fopen('php://stderr', 'ab') : $this->debug;
395
        } elseif (!$this->debugOverride && static::$staticDebug) {
396
            return (static::$staticDebug === true) ? fopen('php://stderr', 'ab') : static::$staticDebug;
397
        }
398
399 105
        return false;
400
    }
401 105
402 91
    /**
403
     * Debugging status for the current request
404
     *
405 16
     * @return bool|resource
406 7
     */
407
    protected function isDebug()
408
    {
409 11
        if (($this->debugOverride && !$this->debug) || (!$this->debugOverride && !static::$staticDebug)) {
410
            return false;
411
        }
412
413
        if ($this->debugOverride && $this->debug) {
414
            return $this->debug;
415
        }
416
417 105
        return static::$staticDebug;
418
    }
419 105
420 91
    /**
421
     * Verbose status for the current request
422
     *
423 14
     * @return array|bool|resource
424 2
     */
425
    protected function isVerbose()
426
    {
427 12
        if (($this->verboseOverride && !$this->verbose) || (!$this->verboseOverride && !static::$staticVerbose)) {
428
            return false;
429
        }
430
431
        if ($this->verboseOverride && $this->verbose) {
432
            return $this->verbose;
433
        }
434
435
        return static::$staticVerbose;
436 131
    }
437
438 131
    /**
439 131
     * Set the Authentication instance
440 113
     *
441
     * @param array $config
442
     * @param Authentication|null $authentication
443 131
     */
444 42
    protected function setAuthentication(array $config, Authentication $authentication = null)
445
    {
446
        $this->authentication = $authentication;
447 131
        if ($authentication === null) {
448 42
            $this->authentication = new Authentication();
449
        }
450 131
451
        if (isset($config['timestamp'])) {
452
            $this->authentication->setTimestamp($config['timestamp']);
453
        }
454
455
        if (isset($config['nonce'])) {
456
            $this->authentication->setNonce($config['nonce']);
457
        }
458
    }
459 131
460
    /**
461 131
     * Set the Authentication Handler
462
     *
463 131
     * @param array $config
464 131
     * @param Authentication|null $authentication
465 131
     * @return array
466 29
     */
467
    protected function setAuthenticationHandler(array $config, Authentication $authentication = null)
468
    {
469 131
        $this->setAuthentication($config, $authentication);
470
471
        $authenticationHandler = new AuthenticationHandler();
472 131
        $authenticationHandler->setSigner($this->authentication);
473 29
        if (!isset($config['handler'])) {
474
            $config['handler'] = \GuzzleHttp\HandlerStack::create();
475 29
        }
476
        try {
477 131
            if (!($config['handler'] instanceof \GuzzleHttp\HandlerStack)) {
478
                $config['handler'] = \GuzzleHttp\HandlerStack::create($config['handler']);
479
            }
480
            $config['handler']->before('history', $authenticationHandler, 'authentication');
481
        } catch (\InvalidArgumentException $e) {
482
            // history middleware not added yet
483
            $config['handler']->push($authenticationHandler, 'authentication');
484
        }
485
        return $config;
486 131
    }
487
488 131
    /**
489 129
     * Set timeout and base_uri options
490
     *
491
     * @param array $config
492 131
     * @return mixed
493 2
     */
494 2
    protected function setBasicOptions(array $config)
495
    {
496 129
        if (!isset($config['timeout'])) {
497
            $config['timeout'] = static::DEFAULT_REQUEST_TIMEOUT;
498
        }
499
500
        if (isset($config['base_uri']) && strpos($config['base_uri'], 'http') === false) {
501
            $config['base_uri'] = 'https://' . $config['base_uri'];
502
            return $config;
503
        }
504
        return $config;
505
    }
506
507
    /**
508
     * Set values on the private \GuzzleHttp\Client->config
509
     *
510
     * This is a terrible hack, and illustrates why making
511
     * anything private makes it difficult to extend, and impossible
512 4
     * when there is no setter.
513
     *
514 4
     * @param string $what Config option to set
515 4
     * @param mixed $value Value to set the option to
516
     * @return void
517 4
     */
518 4
    protected function setConfigOption($what, $value)
519 4
    {
520
        $closure = function () use ($what, $value) {
521
            /* @var $this \GuzzleHttp\Client */
522
            $this->config[$what] = $value;
523
        };
524
525
        $closure = $closure->bindTo($this, \GuzzleHttp\Client::class);
526
        $closure();
527
    }
528 16
529
    /**
530
     * Add the Debug handler to the HandlerStack
531 16
     *
532 6
     * @param array $options Guzzle Options
533
     * @param bool|resource|null $fp Stream to write to
534
     * @return array
535 16
     */
536
    protected function setDebugHandler($options, $fp = null)
537
    {
538 16
        try {
539 1
            if (is_bool($fp)) {
540
                $fp = null;
541
            }
542 16
543
            $handler = $this->getConfig('handler');
544
            // if we have a default handler, and we've already created a DebugHandler
545
            // we can bail out now (or we will add another one to the stack)
546 16
            if ($handler && $this->debugHandler) {
547
                return $options;
548
            }
549
550 16
            if (isset($options['handler'])) {
551 16
                $handler = $options['handler'];
552
            }
553
554 16
            if ($handler === null) {
555
                $handler = \GuzzleHttp\HandlerStack::create();
556
            }
557
558
            if (!$this->debugHandler) {
559 16
                $this->debugHandler = new DebugHandler($fp);
560
            }
561 16
562
            $handler->after('allow_redirects', $this->debugHandler, 'debug');
563
        } catch (\InvalidArgumentException $e) {
564
            $handler->push($this->debugHandler, 'debug');
0 ignored issues
show
Bug introduced by
The variable $handler does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
565
        }
566
567
        $options['handler'] = $handler;
568
569
        return $options;
570
    }
571 24
572
    /**
573
     * Add the Log handler to the HandlerStack
574 24
     *
575 6
     * @param \GuzzleHttp\HandlerStack $handlerStack
576
     * @param callable $logHandler
577 6
     * @return $this
578
     */
579
    protected function setLogHandler(\GuzzleHttp\HandlerStack $handlerStack, callable $logHandler)
580
    {
581
        try {
582
            $handlerStack->after('history', $logHandler, 'logger');
583 24
        } catch (\InvalidArgumentException $e) {
584
            try {
585
                $handlerStack->before('allow_redirects', $logHandler, 'logger');
586
            } catch (\InvalidArgumentException $e) {
587
                $handlerStack->push($logHandler, 'logger');
588
            }
589
        }
590
591
        return $this;
592
    }
593 14
594
    /**
595
     * Add the Verbose handler to the HandlerStack
596 14
     *
597 11
     * @param array $options Guzzle Options
598 3
     * @param bool|resource|array|null $fp Stream to write to
599 1
     * @return array
600
     */
601
    protected function setVerboseHandler($options, $fp = null)
602 14
    {
603
        try {
604
            if (is_bool($fp) || $fp === null) {
605 14
                $fp = ['outputStream' => null, 'errorStream' => null];
606 3
            } elseif (!is_array($fp)) {
607
                $fp = ['outputStream' => $fp, 'errorStream' => $fp];
608
            }
609 14
610 1
            $handler = $this->getConfig('handler');
611
            // if we have a default handler, and we've already created a VerboseHandler
612
            // we can bail out now (or we will add another one to the stack)
613 14
            if ($handler && $this->verboseHandler) {
614
                return $options;
615
            }
616
617 14
            if (isset($options['handler'])) {
618 14
                $handler = $options['handler'];
619
            }
620
621 14
            if ($handler === null) {
622
                $handler = \GuzzleHttp\HandlerStack::create();
623
            }
624
625
            if (!$this->verboseHandler) {
626 14
                $this->verboseHandler = new VerboseHandler(array_shift($fp), array_shift($fp));
627
            }
628 14
629
            $handler->after('allow_redirects', $this->verboseHandler, 'verbose');
630
        } catch (\InvalidArgumentException $e) {
631
            $handler->push($this->verboseHandler, 'verbose');
0 ignored issues
show
Bug introduced by
The variable $handler does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
632
        }
633
634
        $options['handler'] = $handler;
635
636
        return $options;
637 105
    }
638
639 105
    /**
640
     * Set request specific options
641 105
     *
642 63
     * @param array $options
643
     * @return array
644
     */
645 105
    protected function setRequestOptions(array $options)
646
    {
647
        if (isset($options['timestamp'])) {
648
            $this->authentication->setTimestamp($options['timestamp']);
649 105
        } elseif (!$this->getConfig('timestamp')) {
650 3
            $this->authentication->setTimestamp();
651
        }
652
653 105
        if (isset($options['nonce'])) {
654 14
            $this->authentication->setNonce($options['nonce']);
655
        }
656
657 105
        if (isset($options['handler'])) {
658 105
            $options = $this->setAuthenticationHandler($options, $this->authentication);
659 16
        }
660
661
        if ($fp = $this->isVerbose()) {
662 105
            $options = $this->setVerboseHandler($options, $fp);
663 2
        }
664 2
665
        $options['debug'] = $this->getDebugOption($options);
666
        if ($fp = $this->isDebug()) {
667 103
            $options = $this->setDebugHandler($options, $fp);
668
        }
669
670
        if ($this->logger && isset($options['handler'])) {
671
            $this->setLogHandler($options['handler'], $this->logger);
672
            return $options;
673
        }
674
675
        return $options;
676
    }
677
}
678