Completed
Pull Request — master (#31)
by
unknown
03:01
created

Client::setAuth()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
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 View Code Duplication
        if (isset($_ENV['AKAMAI_CLI']) && isset($_ENV['AKAMAI_CLI_VERSION'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
115
            $config['headers']['User-Agent'] .= " AkamaiCLI/" . $_ENV['AKAMAI_CLI_VERSION'];
116
        }
117
118 131 View Code Duplication
        if (isset($_ENV['AKAMAI_CLI_COMMAND'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
119
            $config['headers']['User-Agent'] .= " AkamaiCLI-" . $_ENV['AKAMAI_CLI_COMMAND'] . "/" . $_ENV['AKAMAI_CLI_COMMAND'];
120
        }
121
122 131
        parent::__construct($config);
123 131
    }
124
125
    /**
126
     * Make an Asynchronous request
127
     *
128
     * @param string $method
129
     * @param string $uri
130
     * @param array $options
131
     * @return \GuzzleHttp\Promise\PromiseInterface
132
     * @throws \GuzzleHttp\Exception\GuzzleException
133
     */
134 77
    public function requestAsync($method, $uri = null, array $options = [])
135
    {
136 77
        $options = $this->setRequestOptions($options);
137
138 77
        $query = parse_url($uri, PHP_URL_QUERY);
139 77
        if (!empty($query)) {
140 1
            $uri = substr($uri, 0, (strlen($query)+1) * -1);
141 1
            parse_str($query, $options['query']);
142
        }
143
144 77
        return parent::requestAsync($method, $uri, $options);
145
    }
146
147
    /**
148
     * Send an Asynchronous HTTP request
149
     *
150
     * @param \Psr\Http\Message\RequestInterface $request The HTTP request
151
     * @param array $options Request options
152
     *
153
     * @return \GuzzleHttp\Promise\PromiseInterface
154
     */
155 28
    public function sendAsync(\Psr\Http\Message\RequestInterface $request, array $options = [])
156
    {
157 28
        $options = $this->setRequestOptions($options);
158
159 28
        return parent::sendAsync($request, $options);
160
    }
161
162
    /**
163
     * Set Akamai {OPEN} Authentication Credentials
164
     *
165
     * @param string $client_token
166
     * @param string $client_secret
167
     * @param string $access_token
168
     * @return $this
169
     */
170 60
    public function setAuth($client_token, $client_secret, $access_token)
171
    {
172 60
        $this->authentication->setAuth($client_token, $client_secret, $access_token);
173
174 60
        return $this;
175
    }
176
177
    /**
178
     * Specify the headers to include when signing the request
179
     *
180
     * This is specified by the API, currently no APIs use this
181
     * feature.
182
     *
183
     * @param array $headers
184
     * @return $this
185
     */
186 42
    public function setHeadersToSign(array $headers)
187
    {
188 42
        $this->authentication->setHeadersToSign($headers);
189
190 42
        return $this;
191
    }
192
193
    /**
194
     * Set the max body size
195
     *
196
     * @param int $max_body_size
197
     * @return $this
198
     */
199 42
    public function setMaxBodySize($max_body_size)
200
    {
201 42
        $this->authentication->setMaxBodySize($max_body_size);
202
203 42
        return $this;
204
    }
205
206
    /**
207
     * Set Request Host
208
     *
209
     * @param string $host
210
     * @return $this
211
     */
212 2
    public function setHost($host)
213
    {
214 2
        if (substr($host, -1) === '/') {
215 2
            $host = substr($host, 0, -1);
216
        }
217
218 2
        $headers = $this->getConfig('headers');
219 2
        $headers['Host'] = $host;
220 2
        $this->setConfigOption('headers', $headers);
221
222 2
        if (strpos('/', $host) === false) {
223 2
            $host = 'https://' . $host;
224
        }
225 2
        $this->setConfigOption('base_uri', $host);
226
227 2
        return $this;
228
    }
229
230
    /**
231
     * Set the HTTP request timeout
232
     *
233
     * @param int $timeout_in_seconds
234
     * @return $this
235
     */
236 2
    public function setTimeout($timeout_in_seconds)
237
    {
238 2
        $this->setConfigOption('timeout', $timeout_in_seconds);
239
240 2
        return $this;
241
    }
242
243
    /**
244
     * Print formatted JSON responses to output
245
     *
246
     * @param bool|resource $enable
247
     * @return $this
248
     */
249 4
    public function setInstanceVerbose($enable)
250
    {
251 4
        $this->verboseOverride = true;
252 4
        $this->verbose = $enable;
253 4
        return $this;
254
    }
255
256
    /**
257
     * Print HTTP requests/responses to output
258
     *
259
     * @param bool|resource $enable
260
     * @return $this
261
     */
262 10
    public function setInstanceDebug($enable)
263
    {
264 10
        $this->debugOverride = true;
265 10
        $this->debug = $enable;
266 10
        return $this;
267
    }
268
269
    /**
270
     * Set a PSR-3 compatible logger (or use monolog by default)
271
     *
272
     * @param \Psr\Log\LoggerInterface $logger
273
     * @param string $messageFormat Message format
274
     * @return $this
275
     */
276 24
    public function setLogger(
277
        \Psr\Log\LoggerInterface $logger = null,
278
        $messageFormat = \GuzzleHttp\MessageFormatter::CLF
279
    ) {
280 24
        if ($logger === null) {
281 2
            $handler = new \Monolog\Handler\ErrorLogHandler(\Monolog\Handler\ErrorLogHandler::SAPI);
282 2
            $handler->setFormatter(new \Monolog\Formatter\LineFormatter('%message%'));
283 2
            $logger = new \Monolog\Logger('HTTP Log', [$handler]);
284
        }
285
286 24
        $formatter = new \GuzzleHttp\MessageFormatter($messageFormat);
287
288 24
        $handler = \GuzzleHttp\Middleware::log($logger, $formatter);
289 24
        $this->logger = $handler;
290
291 24
        $handlerStack = $this->getConfig('handler');
292 24
        $this->setLogHandler($handlerStack, $handler);
293
294 24
        return $this;
295
    }
296
297
    /**
298
     * Add logger using a given filename/format
299
     *
300
     * @param string $filename
301
     * @param string $format
302
     * @return \Akamai\Open\EdgeGrid\Client|bool
303
     */
304 4
    public function setSimpleLog($filename, $format = '{code}')
305
    {
306 4
        if ($this->logger && !($this->logger instanceof \Monolog\Logger)) {
307 2
            return false;
308
        }
309
310 2
        $handler = new \Monolog\Handler\StreamHandler($filename);
311 2
        $handler->setFormatter(new \Monolog\Formatter\LineFormatter('%message%'));
312 2
        $log = new \Monolog\Logger('HTTP Log', [$handler]);
313
314 2
        return $this->setLogger($log, $format);
315
    }
316
317
    /**
318
     * Create instance using environment (preferred) or .edgerc file (fallback) automatically.
319
     *
320
     * @param string $section
321
     * @param null $path
322
     * @return Client
323
     * @throws \Akamai\Open\EdgeGrid\Authentication\Exception\ConfigException
324
     */
325 10 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...
326
    {
327 10
        $auth = \Akamai\Open\EdgeGrid\Authentication::createInstance($section, $path);
328
329 2
        if ($host = $auth->getHost()) {
330 2
            $config['base_uri'] = 'https://' .$host;
331
        }
332
333 2
        return new static($config, $auth);
334
    }
335
336 12 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...
337
    {
338 12
        $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEnv($section);
339
340 8
        if ($host = $auth->getHost()) {
341 8
            $config['base_uri'] = 'https://' . $host;
342
        }
343
344 8
        return new static($config, $auth);
345
    }
346
347
    /**
348
     * Factory method to create a client using credentials from `.edgerc`
349
     *
350
     * Automatically checks your HOME directory, and the current working
351
     * directory for credentials, if no path is supplied.
352
     *
353
     * @param string $section Credential section to use
354
     * @param string $path Path to .edgerc credentials file
355
     * @param array $config Options to pass to the constructor/guzzle
356
     * @return \Akamai\Open\EdgeGrid\Client
357
     */
358 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...
359
    {
360 8
        $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile($section, $path);
361
362 8
        if ($host = $auth->getHost()) {
363 8
            $config['base_uri'] = 'https://' . $host;
364
        }
365
366 8
        return new static($config, $auth);
367
    }
368
369
    /**
370
     * Print HTTP requests/responses to STDOUT
371
     *
372
     * @param bool|resource $enable
373
     */
374 161
    public static function setDebug($enable)
375
    {
376 161
        self::$staticDebug = $enable;
377 161
    }
378
379
    /**
380
     * Print formatted JSON responses to STDOUT
381
     *
382
     * @param bool|resource|array $enable
383
     */
384 169
    public static function setVerbose($enable)
385
    {
386 169
        self::$staticVerbose = $enable;
387 169
    }
388
389
    /**
390
     * Handle debug option
391
     *
392
     * @param array $config
393
     * @return bool|resource
394
     */
395 105
    protected function getDebugOption(array $config)
396
    {
397 105
        if (isset($config['debug'])) {
398 2
            return ($config['debug'] === true) ? fopen('php://stderr', 'ab') : $config['debug'];
399
        }
400
401 103
        if ($this->debugOverride && $this->debug) {
402 5
            return ($this->debug === true) ? fopen('php://stderr', 'ab') : $this->debug;
403 98
        } elseif (!$this->debugOverride && static::$staticDebug) {
404 9
            return (static::$staticDebug === true) ? fopen('php://stderr', 'ab') : static::$staticDebug;
405
        }
406
407 89
        return false;
408
    }
409
410
    /**
411
     * Debugging status for the current request
412
     *
413
     * @return bool|resource
414
     */
415 105
    protected function isDebug()
416
    {
417 105
        if (($this->debugOverride && !$this->debug) || (!$this->debugOverride && !static::$staticDebug)) {
418 91
            return false;
419
        }
420
421 16
        if ($this->debugOverride && $this->debug) {
422 7
            return $this->debug;
423
        }
424
425 11
        return static::$staticDebug;
426
    }
427
428
    /**
429
     * Verbose status for the current request
430
     *
431
     * @return array|bool|resource
432
     */
433 105
    protected function isVerbose()
434
    {
435 105
        if (($this->verboseOverride && !$this->verbose) || (!$this->verboseOverride && !static::$staticVerbose)) {
436 91
            return false;
437
        }
438
439 14
        if ($this->verboseOverride && $this->verbose) {
440 2
            return $this->verbose;
441
        }
442
443 12
        return static::$staticVerbose;
444
    }
445
446
    /**
447
     * Set the Authentication instance
448
     *
449
     * @param array $config
450
     * @param Authentication|null $authentication
451
     */
452 131
    protected function setAuthentication(array $config, Authentication $authentication = null)
453
    {
454 131
        $this->authentication = $authentication;
455 131
        if ($authentication === null) {
456 113
            $this->authentication = new Authentication();
457
        }
458
459 131
        if (isset($config['timestamp'])) {
460 42
            $this->authentication->setTimestamp($config['timestamp']);
461
        }
462
463 131
        if (isset($config['nonce'])) {
464 42
            $this->authentication->setNonce($config['nonce']);
465
        }
466 131
    }
467
468
    /**
469
     * Set the Authentication Handler
470
     *
471
     * @param array $config
472
     * @param Authentication|null $authentication
473
     * @return array
474
     */
475 131
    protected function setAuthenticationHandler(array $config, Authentication $authentication = null)
476
    {
477 131
        $this->setAuthentication($config, $authentication);
478
479 131
        $authenticationHandler = new AuthenticationHandler();
480 131
        $authenticationHandler->setSigner($this->authentication);
481 131
        if (!isset($config['handler'])) {
482 29
            $config['handler'] = \GuzzleHttp\HandlerStack::create();
483
        }
484
        try {
485 131
            if (!($config['handler'] instanceof \GuzzleHttp\HandlerStack)) {
486
                $config['handler'] = \GuzzleHttp\HandlerStack::create($config['handler']);
487
            }
488 131
            $config['handler']->before('history', $authenticationHandler, 'authentication');
489 29
        } catch (\InvalidArgumentException $e) {
490
            // history middleware not added yet
491 29
            $config['handler']->push($authenticationHandler, 'authentication');
492
        }
493 131
        return $config;
494
    }
495
496
    /**
497
     * Set timeout and base_uri options
498
     *
499
     * @param array $config
500
     * @return mixed
501
     */
502 131
    protected function setBasicOptions(array $config)
503
    {
504 131
        if (!isset($config['timeout'])) {
505 129
            $config['timeout'] = static::DEFAULT_REQUEST_TIMEOUT;
506
        }
507
508 131
        if (isset($config['base_uri']) && strpos($config['base_uri'], 'http') === false) {
509 2
            $config['base_uri'] = 'https://' . $config['base_uri'];
510 2
            return $config;
511
        }
512 129
        return $config;
513
    }
514
515
    /**
516
     * Set values on the private \GuzzleHttp\Client->config
517
     *
518
     * This is a terrible hack, and illustrates why making
519
     * anything private makes it difficult to extend, and impossible
520
     * when there is no setter.
521
     *
522
     * @param string $what Config option to set
523
     * @param mixed $value Value to set the option to
524
     * @return void
525
     */
526
    protected function setConfigOption($what, $value)
527
    {
528 4
        $closure = function () use ($what, $value) {
529
            /* @var $this \GuzzleHttp\Client */
530 4
            $this->config[$what] = $value;
531 4
        };
532
533 4
        $closure = $closure->bindTo($this, \GuzzleHttp\Client::class);
534 4
        $closure();
535 4
    }
536
537
    /**
538
     * Add the Debug handler to the HandlerStack
539
     *
540
     * @param array $options Guzzle Options
541
     * @param bool|resource|null $fp Stream to write to
542
     * @return array
543
     */
544 16
    protected function setDebugHandler($options, $fp = null)
545
    {
546
        try {
547 16
            if (is_bool($fp)) {
548 6
                $fp = null;
549
            }
550
551 16
            $handler = $this->getConfig('handler');
552
            // if we have a default handler, and we've already created a DebugHandler
553
            // we can bail out now (or we will add another one to the stack)
554 16
            if ($handler && $this->debugHandler) {
555 1
                return $options;
556
            }
557
558 16
            if (isset($options['handler'])) {
559
                $handler = $options['handler'];
560
            }
561
562 16
            if ($handler === null) {
563
                $handler = \GuzzleHttp\HandlerStack::create();
564
            }
565
566 16
            if (!$this->debugHandler) {
567 16
                $this->debugHandler = new DebugHandler($fp);
568
            }
569
570 16
            $handler->after('allow_redirects', $this->debugHandler, 'debug');
571
        } catch (\InvalidArgumentException $e) {
572
            $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...
573
        }
574
575 16
        $options['handler'] = $handler;
576
577 16
        return $options;
578
    }
579
580
    /**
581
     * Add the Log handler to the HandlerStack
582
     *
583
     * @param \GuzzleHttp\HandlerStack $handlerStack
584
     * @param callable $logHandler
585
     * @return $this
586
     */
587 24
    protected function setLogHandler(\GuzzleHttp\HandlerStack $handlerStack, callable $logHandler)
588
    {
589
        try {
590 24
            $handlerStack->after('history', $logHandler, 'logger');
591 6
        } catch (\InvalidArgumentException $e) {
592
            try {
593 6
                $handlerStack->before('allow_redirects', $logHandler, 'logger');
594
            } catch (\InvalidArgumentException $e) {
595
                $handlerStack->push($logHandler, 'logger');
596
            }
597
        }
598
599 24
        return $this;
600
    }
601
602
    /**
603
     * Add the Verbose handler to the HandlerStack
604
     *
605
     * @param array $options Guzzle Options
606
     * @param bool|resource|array|null $fp Stream to write to
607
     * @return array
608
     */
609 14
    protected function setVerboseHandler($options, $fp = null)
610
    {
611
        try {
612 14
            if (is_bool($fp) || $fp === null) {
613 11
                $fp = ['outputStream' => null, 'errorStream' => null];
614 3
            } elseif (!is_array($fp)) {
615 1
                $fp = ['outputStream' => $fp, 'errorStream' => $fp];
616
            }
617
618 14
            $handler = $this->getConfig('handler');
619
            // if we have a default handler, and we've already created a VerboseHandler
620
            // we can bail out now (or we will add another one to the stack)
621 14
            if ($handler && $this->verboseHandler) {
622 3
                return $options;
623
            }
624
625 14
            if (isset($options['handler'])) {
626 1
                $handler = $options['handler'];
627
            }
628
629 14
            if ($handler === null) {
630
                $handler = \GuzzleHttp\HandlerStack::create();
631
            }
632
633 14
            if (!$this->verboseHandler) {
634 14
                $this->verboseHandler = new VerboseHandler(array_shift($fp), array_shift($fp));
635
            }
636
637 14
            $handler->after('allow_redirects', $this->verboseHandler, 'verbose');
638
        } catch (\InvalidArgumentException $e) {
639
            $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...
640
        }
641
642 14
        $options['handler'] = $handler;
643
644 14
        return $options;
645
    }
646
647
    /**
648
     * Set request specific options
649
     *
650
     * @param array $options
651
     * @return array
652
     */
653 105
    protected function setRequestOptions(array $options)
654
    {
655 105
        if (isset($options['timestamp'])) {
656
            $this->authentication->setTimestamp($options['timestamp']);
657 105
        } elseif (!$this->getConfig('timestamp')) {
658 63
            $this->authentication->setTimestamp();
659
        }
660
661 105
        if (isset($options['nonce'])) {
662
            $this->authentication->setNonce($options['nonce']);
663
        }
664
665 105
        if (isset($options['handler'])) {
666 3
            $options = $this->setAuthenticationHandler($options, $this->authentication);
667
        }
668
669 105
        if ($fp = $this->isVerbose()) {
670 14
            $options = $this->setVerboseHandler($options, $fp);
671
        }
672
673 105
        $options['debug'] = $this->getDebugOption($options);
674 105
        if ($fp = $this->isDebug()) {
675 16
            $options = $this->setDebugHandler($options, $fp);
676
        }
677
678 105
        if ($this->logger && isset($options['handler'])) {
679 2
            $this->setLogHandler($options['handler'], $this->logger);
680 2
            return $options;
681
        }
682
683 103
        return $options;
684
    }
685
}
686