Socket::getHandleReadFunction()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 4
nc 4
nop 0
crap 3
1
<?php
2
3
namespace Dazzle\Socket;
4
5
use Dazzle\Loop\LoopInterface;
6
use Dazzle\Stream\Stream;
7
use Dazzle\Throwable\Exception\Logic\InstantiationException;
8
use Dazzle\Throwable\Exception\Runtime\ExecutionException;
9
use Dazzle\Throwable\Exception\LogicException;
10
use Error;
11
use Exception;
12
13
class Socket extends Stream implements SocketInterface
14
{
15
    /**
16
     * @var string
17
     */
18
    const TYPE_UNIX = 'unix_socket';
19
20
    /**
21
     * @var string
22
     */
23
    const TYPE_TCP = 'tcp_socket/ssl';
24
25
    /**
26
     * @var string
27
     */
28
    const TYPE_UDP = 'udp_socket';
29
30
    /**
31
     * @var string
32
     */
33
    const TYPE_UNKNOWN = 'Unknown';
34
35
    /**
36
     * @var int
37
     */
38
    const CRYPTO_TYPE_UNKNOWN = 0;
39
40
    /**
41
     * @var int
42
     */
43
    const CRYPTO_TYPE_SERVER = 1;
44
45
    /**
46
     * @var int
47
     */
48
    const CRYPTO_TYPE_CLIENT = 2;
49
50
    /**
51
     * @var mixed
52
     */
53
    const CONFIG_DEFAULT_SSL = false;
54
55
    /**
56
     * @var mixed
57
     */
58
    const CONFIG_DEFAULT_SSL_METHOD = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
59
60
    /**
61
     * @var mixed
62
     */
63
    const CONFIG_DEFAULT_SSL_NAME = '';
64
65
    /**
66
     * @var mixed
67
     */
68
    const CONFIG_DEFAULT_SSL_VERIFY_SIGN = false;
69
70
    /**
71
     * @var mixed
72
     */
73
    const CONFIG_DEFAULT_SSL_VERIFY_PEER = false;
74
75
    /**
76
     * @var mixed
77
     */
78
    const CONFIG_DEFAULT_SSL_VERIFY_DEPTH = 10;
79
80
    /**
81
     * @var int
82
     */
83
    protected $crypto = 0;
84
85
    /**
86
     * @var int
87
     */
88
    protected $cryptoMethod = 0;
89
90
    /**
91
     * @var array
92
     */
93
    protected $config = [];
94
95
    /**
96
     * @var bool[]
97
     */
98
    private $cachedEndpoint = [];
99
100
    /**
101
     * @param string|resource $endpointOrResource
102
     * @param LoopInterface $loop
103
     * @param mixed[] $config
104
     * @throws InstantiationException
105
     */
106 18
    public function __construct($endpointOrResource, LoopInterface $loop, $config = [])
107
    {
108
        try
109
        {
110 18
            $this->configure($config);
111
112 18
            if (!is_resource($endpointOrResource))
113
            {
114 18
                $endpointOrResource = $this->createClient($endpointOrResource, $config);
0 ignored issues
show
Bug introduced by
It seems like $endpointOrResource defined by $this->createClient($endpointOrResource, $config) on line 114 can also be of type resource; however, Dazzle\Socket\Socket::createClient() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
115
            }
116
117 16
            parent::__construct($endpointOrResource, $loop);
0 ignored issues
show
Documentation introduced by
$loop is of type object<Dazzle\Loop\LoopInterface>, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
118
119 16
            $this->read();
120
        }
121 2
        catch (Error $ex)
122
        {
123
            throw new InstantiationException('SocketClient could not be created.', 0, $ex);
124
        }
125 2
        catch (Exception $ex)
126
        {
127 2
            throw new InstantiationException('SocketClient could not be created.', 0, $ex);
128
        }
129 16
    }
130
131
    /**
132
     * @override
133
     * @inheritDoc
134
     */
135 1
    public function stop()
136
    {
137 1
        $this->close();
138 1
    }
139
140
    /**
141
     * @override
142
     * @inheritDoc
143
     */
144 5
    public function getLocalEndpoint()
145
    {
146 5
        return $this->parseEndpoint(false);
147
    }
148
149
    /**
150
     * @override
151
     * @inheritDoc
152
     */
153 5
    public function getRemoteEndpoint()
154
    {
155 5
        return $this->parseEndpoint(true);
156
    }
157
158
    /**
159
     * @override
160
     * @inheritDoc
161
     */
162 3
    public function getLocalAddress()
163
    {
164 3
        $endpoint = explode('://', $this->getLocalEndpoint(), 2);
165
166 3
        return isset($endpoint[1]) ? $endpoint[1] : $endpoint[0];
167
    }
168
169
    /**
170
     * @override
171
     * @inheritDoc
172
     */
173 1
    public function getLocalHost()
174
    {
175 1
        $address = explode(':', $this->getLocalAddress(), 2);
176
177 1
        return $address[0];
178
    }
179
180
    /**
181
     * @override
182
     * @inheritDoc
183
     */
184 1
    public function getLocalPort()
185
    {
186 1
        $address = explode(':', $this->getLocalAddress(), 2);
187
188 1
        return isset($address[1]) ? $address[1] : '';
189
    }
190
191
    /**
192
     * @override
193
     * @inheritDoc
194
     */
195 1
    public function getLocalProtocol()
196
    {
197 1
        $endpoint = explode('://', $this->getLocalEndpoint(), 2);
198
199 1
        return isset($endpoint[0]) ? $endpoint[0] : '';
200
    }
201
202
    /**
203
     * @override
204
     * @inheritDoc
205
     */
206 3
    public function getRemoteAddress()
207
    {
208 3
        $endpoint = explode('://', $this->getRemoteEndpoint(), 2);
209
210 3
        return isset($endpoint[1]) ? $endpoint[1] : $endpoint[0];
211
    }
212
213
    /**
214
     * @override
215
     * @inheritDoc
216
     */
217 1
    public function getRemoteHost()
218
    {
219 1
        $address = explode(':', $this->getRemoteAddress(), 2);
220
221 1
        return $address[0];
222
    }
223
224
    /**
225
     * @override
226
     * @inheritDoc
227
     */
228 1
    public function getRemotePort()
229
    {
230 1
        $address = explode(':', $this->getRemoteAddress(), 2);
231
232 1
        return isset($address[1]) ? $address[1] : '';
233
    }
234
235
    /**
236
     * @override
237
     * @inheritDoc
238
     */
239 1
    public function getRemoteProtocol()
240
    {
241 1
        $endpoint = explode('://', $this->getRemoteEndpoint(), 2);
242
243 1
        return isset($endpoint[0]) ? $endpoint[0] : '';
244
    }
245
246
    /**
247
     * @override
248
     * @inheritDoc
249
     */
250 1
    public function isEncrypted()
251
    {
252 1
        return $this->crypto !== 0;
253
    }
254
255
    /**
256
     * Create the client resource.
257
     *
258
     * This method creates client resource for socket connections.
259
     *
260
     * @param string $endpoint
261
     * @param mixed[] $config
262
     * @return resource
263
     * @throws LogicException
264
     */
265 18
    protected function createClient($endpoint, $config = [])
266
    {
267 18
        $ssl = $this->config['ssl'];
268 18
        $name = $this->config['ssl_name'];
269 18
        $verifySign = $this->config['ssl_verify_sign'];
270 18
        $verifyPeer = $this->config['ssl_verify_peer'];
271 18
        $verifyDepth = $this->config['ssl_verify_depth'];
272
273 18
        $context = [];
274 18
        $context['socket'] = [
275 18
            'connect' => $endpoint
276
        ];
277 18
        $context['ssl'] = [
278 18
            'capture_peer_cert' => true,
279
            'capture_peer_chain' => true,
280
            'capture_peer_cert_chain' => true,
281 18
            'allow_self_signed' => !$verifySign,
282 18
            'verify_peer' => $verifyPeer,
283 18
            'verify_peer_name' => $verifyPeer,
284 18
            'verify_depth' => $verifyDepth,
285 18
            'SNI_enabled' => $name !== '',
286 18
            'SNI_server_name' => $name,
287 18
            'peer_name' => $name,
288
            'disable_compression' => true,
289
            'honor_cipher_order' => true,
290
        ];
291
292 18
        if ($ssl && isset($config['ssl_cafile']))
293
        {
294
            $context['ssl']['cafile'] = $config['ssl_cafile'];
295
        }
296
297 18
        if ($ssl && isset($config['ssl_capath']))
298
        {
299
            $context['ssl']['capath'] = $config['ssl_capath'];
300
        }
301
302 18
        $context = stream_context_create($context);
303
        // Error reporting suppressed since stream_socket_client() emits an E_WARNING on failure.
304 18
        $socket = @stream_socket_client(
305 18
            $endpoint,
306 18
            $errno,
307 18
            $errstr,
308 18
            0, // Timeout does not apply for async connect.
309 18
            STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT,
310 18
            $context
311
        );
312
313 18 View Code Duplication
        if (!$socket || $errno > 0)
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...
314
        {
315 2
            throw new LogicException(
316 2
                sprintf('Could not connect socket [%s] because of error [%d; %s]', $endpoint, $errno, $errstr)
317
            );
318
        }
319
320 16
        stream_set_blocking($socket, false);
321
322 16
        return $socket;
323
    }
324
325
    /**
326
     * Handle socket encryption.
327
     *
328
     * @internal
329
     */
330 1
    public function handleEncrypt()
331
    {
332 1
        $ex = null;
333
334
        try
335
        {
336 1
            if ($this->isEncrypted())
337
            {
338
                return;
339
            }
340
341 1
            $this->encrypt($this->config['ssl_method']);
342
343 1
            if ($this->isEncrypted())
344
            {
345 1
                $this->pause();
0 ignored issues
show
Bug introduced by
The method pause() does not seem to exist on object<Dazzle\Socket\Socket>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
346 1
                $this->resume();
0 ignored issues
show
Bug introduced by
The method resume() does not seem to exist on object<Dazzle\Socket\Socket>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
347
            }
348
        }
349
        catch (Error $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
350
        {}
351
        catch (Exception $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
352
        {}
353
354 1
        if ($ex !== null)
355
        {
356
            $this->close();
357
            $this->emit('error', [ $this, $ex ]);
358
        }
359 1
    }
360
361
    /**
362
     * @internal
363
     * @override
364
     * @inheritDoc
365
     */
366 3
    public function handleRead()
367
    {
368 3
        $ex = null;
369
370
        try
371
        {
372 3
            $data = fread($this->resource, $this->bufferSize);
373
374 3
            if ($data !== '' && $data !== false)
375
            {
376 3
                $this->emit('data', [ $this, $data ]);
377 3
                $this->emit('end', [ $this ]);
378
            }
379
380 3
            if ($data === '' || $data === false || !is_resource($this->resource) || feof($this->resource))
381
            {
382 3
                $this->close();
383
            }
384
        }
385
        catch (Error $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
386
        {}
387
        catch (Exception $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
388
        {}
389
390 3
        if ($ex !== null)
391
        {
392
            $this->emit('error', [ $this, $ex ]);
393
        }
394 3
    }
395
396
    /**
397
     * @internal
398
     * @override
399
     * @inheritDoc
400
     */
401 3
    public function handleWrite()
402
    {
403 3
        $ex = null;
404
405
        try
406
        {
407 3
            parent::handleWrite();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Dazzle\Stream\Stream as the method handleWrite() does only exist in the following sub-classes of Dazzle\Stream\Stream: Dazzle\Socket\Socket, Dazzle\Stream\AsyncStream. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
408
        }
409
        catch (Error $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
410
        {}
411
        catch (Exception $ex)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
412
        {}
413
414 3
        if ($ex !== null)
415
        {
416
            $this->emit('error', [ $this, $ex ]);
417
        }
418 3
    }
419
420
    /**
421
     * @internal
422
     * @override
423
     * @inheritDoc
424
     */
425 16
    public function handleClose()
426
    {
427 16
        $this->pause();
0 ignored issues
show
Bug introduced by
The method pause() does not seem to exist on object<Dazzle\Socket\Socket>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
428
429 16
        if (is_resource($this->resource))
430
        {
431
            // http://chat.stackoverflow.com/transcript/message/7727858#7727858
432 16
            stream_socket_shutdown($this->resource, STREAM_SHUT_RDWR);
433 16
            stream_set_blocking($this->resource, 0);
434 16
            fclose($this->resource);
435
        }
436 16
    }
437
438
    /**
439
     * Get function that should be invoked on read event.
440
     *
441
     * @return callable
442
     */
443 16
    protected function getHandleReadFunction()
444
    {
445 16
        return $this->config['ssl'] === true && !$this->isEncrypted()
446 1
            ? [ $this, 'handleEncrypt' ]
447 16
            : [ $this, 'handleRead' ];
448
    }
449
450
    /**
451
     * Get function that should be invoked on write event.
452
     *
453
     * @return callable
454
     */
455 3
    protected function getHandleWriteFunction()
456
    {
457 3
        return $this->config['ssl'] === true && !$this->isEncrypted()
458 1
            ? [ $this, 'handleEncrypt' ]
459 3
            : [ $this, 'handleWrite' ];
460
    }
461
462
    /**
463
     * Configure socket.
464
     *
465
     * @param string[] $config
466
     */
467 18 View Code Duplication
    private function configure($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...
468
    {
469 18
        $this->config = $config;
470
471 18
        $this->configureVariable('ssl');
472 18
        $this->configureVariable('ssl_method');
473 18
        $this->configureVariable('ssl_name');
474 18
        $this->configureVariable('ssl_verify_sign');
475 18
        $this->configureVariable('ssl_verify_peer');
476 18
        $this->configureVariable('ssl_verify_depth');
477 18
    }
478
479
    /**
480
     * Configure config variable.
481
     *
482
     * @param $configKey
483
     */
484 18
    private function configureVariable($configKey)
485
    {
486 18
        $configStaticKey = 'CONFIG_DEFAULT_' . strtoupper($configKey);
487 18
        $this->config[$configKey] = isset($this->config[$configKey]) ? $this->config[$configKey] : constant("static::$configStaticKey");
488 18
    }
489
490
    /**
491
     * @param bool $wantPeer
492
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
493
     */
494 10
    private function parseEndpoint($wantPeer = false)
495
    {
496 10
        $wantIndex = (int)$wantPeer;
497
498 10
        if (isset($this->cachedEndpoint[$wantIndex]))
499
        {
500
            return $this->cachedEndpoint[$wantIndex];
501
        }
502
503 10
        if (get_resource_type($this->resource) === Socket::TYPE_UNKNOWN)
504
        {
505
            return '';
506
        }
507
508 10
        $name = stream_socket_get_name($this->resource, $wantPeer);
509 10
        $type = $this->getStreamType();
510
511 View Code Duplication
        switch ($type)
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...
512
        {
513 10
            case Socket::TYPE_UNIX:
514
                $transport = 'unix://';
515
                $endpoint = $transport . $name;
516
                break;
517
518 10
            case Socket::TYPE_TCP:
519 10
                $transport = 'tcp://';
520 10
                if (substr_count($name, ':') > 1)
521
                {
522
                    $parts = explode(':', $name);
523
                    $count = count($parts);
524
                    $port = $parts[$count - 1];
525
                    unset($parts[$count - 1]);
526
                    $endpoint = $transport.'[' . implode(':', $parts) . ']:' . $port;
527
                }
528
                else
529
                {
530 10
                    $endpoint = $transport . $name;
531
                }
532 10
                break;
533
534
            case Socket::TYPE_UDP:
535
                $transport = 'udp://';
536
                $endpoint = $transport . $name;
537
                break;
538
539
            default:
540
                $endpoint = '';
541
        }
542
543 10
        $this->cachedEndpoint[$wantIndex] = $endpoint;
544
545 10
        return $endpoint;
546
    }
547
548
    /**
549
     * @override
550
     * @inheritDoc
551
     */
552 1
    private function encrypt($method)
553
    {
554 1
        $type = $this->selectCryptoType($method);
555
556 1
        if ($type === self::CRYPTO_TYPE_UNKNOWN)
557
        {
558
            throw new ExecutionException('Socket encryption method is invalid!');
559
        }
560
561 1
        $resource = $this->getResource();
562
563 1
        if ($type === self::CRYPTO_TYPE_SERVER && $this->cryptoMethod === 0)
564
        {
565 1
            $raw = @stream_socket_recvfrom($resource, 11, STREAM_PEEK);
566
567 1
            if ($raw === '')
568
            {
569
                return;
570
            }
571
572 1
            if (11 > strlen($raw))
573
            {
574
                throw new ExecutionException('Failed to read crypto handshake.');
575
            }
576
577 1
            $data = unpack('ctype/nversion/nlength/Nembed/nmax-version', $raw);
578 1
            if (0x16 !== $data['type'])
579
            {
580
                throw new ExecutionException('Invalid crypto handshake.');
581
            }
582
583
            // Check if version was available in $method.
584 1
            $version = $this->selectCryptoVersion($data['max-version']);
585 1
            if ($method & $version)
586
            {
587 1
                $method = $version;
588
            }
589
        }
590
591 1
        $this->cryptoMethod = $method;
592 1
        $result = @stream_socket_enable_crypto($resource, true, $this->cryptoMethod);
593
594 1
        if ($result === 0)
595
        {
596 1
            return;
597
        }
598 1
        else if (!$result)
599
        {
600
            $message = 'Socket encryption failed.';
601
            if ($error = error_get_last())
602
            {
603
                $message .= sprintf(' Errno: %d; %s', $error['type'], $error['message']);
604
            }
605
            throw new ExecutionException($message);
606
        }
607
        else
608
        {
609 1
            $this->crypto = $this->cryptoMethod;
610
        }
611 1
    }
612
613
    /**
614
     * Checks type of crypto.
615
     *
616
     * @param int $version
617
     * @return int
618
     */
619 1
    private function selectCryptoType($version)
620
    {
621
        switch ($version)
622
        {
623 1
            case STREAM_CRYPTO_METHOD_SSLv3_SERVER:
624 1
            case STREAM_CRYPTO_METHOD_TLSv1_0_SERVER:
625 1
            case STREAM_CRYPTO_METHOD_TLSv1_1_SERVER:
626 1
            case STREAM_CRYPTO_METHOD_TLSv1_2_SERVER:
627 1
                return self::CRYPTO_TYPE_SERVER;
628
629 1
            case STREAM_CRYPTO_METHOD_SSLv3_CLIENT:
630 1
            case STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT:
631 1
            case STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT:
632 1
            case STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT:
633 1
                return self::CRYPTO_TYPE_CLIENT;
634
635
            default:
636
                return self::CRYPTO_TYPE_UNKNOWN;
637
        }
638
    }
639
640
    /**
641
     * Returns highest supported crypto method constant based on protocol version identifier.
642
     *
643
     * @param int $version
644
     * @return int
645
     */
646 1
    private function selectCryptoVersion($version)
647
    {
648
        switch ($version)
649
        {
650 1
            case 0x300: return STREAM_CRYPTO_METHOD_SSLv3_SERVER;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
651 1
            case 0x301: return STREAM_CRYPTO_METHOD_TLSv1_0_SERVER;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
652 1
            case 0x302: return STREAM_CRYPTO_METHOD_TLSv1_1_SERVER;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
653 1
            default:    return STREAM_CRYPTO_METHOD_TLSv1_2_SERVER;
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
654
        }
655
    }
656
}
657