Passed
Push — master ( 23b5cc...9353aa )
by Sébastien
04:46
created

StreamSocket::getConnectTimeout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\Japha\Bridge\Socket;
6
7
use Soluble\Japha\Bridge\Exception\ConnectionException;
8
use Soluble\Japha\Bridge\Exception\InvalidArgumentException;
9
10
class StreamSocket implements StreamSocketInterface
11
{
12
    public const TRANSPORT_SSL = 'ssl';
13
    public const TRANSPORT_TCP = 'tcp';
14
15
    public const REGISTERED_TRANSPORTS = [
16
        self::TRANSPORT_SSL,
17
        self::TRANSPORT_TCP
18
    ];
19
20
    public const DEFAULT_CONTEXT = [
21
        'http' => [
22
            'protocol_version' => '1.1',
23
        ]
24
    ];
25
26
    public const DEFAULT_CONNECT_TIMEOUTS = [
27
        'HOST_127.0.0.1' => 5.0,
28
        'HOST_localhost' => 5.0,
29
        'DEFAULT' => 20.0
30
    ];
31
32
    /**
33
     * @var resource
34
     */
35
    protected $socket;
36
37
    protected $persistent = false;
38
    protected $address;
39
    protected $connectTimeout;
40
    protected $streamContext;
41
    protected $transport;
42
43
    /**
44
     * @param string  $transport      tcp, ssl... see self::TRANSPORT
45
     * @param string  $address        ip:port
46 32
     * @param float   $connectTimeout connection timeout in seconds (double: i.e: 5.0)
47
     * @param mixed[] $streamContext  see stream_context_create()
48
     * @param bool    $persistent     whether to use persistent connections
49
     */
50
    public function __construct(
51
        string $transport,
52
        string $address,
53 32
        float $connectTimeout = null,
54 31
        array $streamContext = self::DEFAULT_CONTEXT,
55 31
        bool $persistent = false
56 31
    ) {
57 31
        $this->setTransport($transport);
58 31
        $this->address = $address;
59 28
        $this->setConnectTimeout($connectTimeout);
60
        $this->streamContext = $streamContext;
61
        $this->persistent = $persistent;
62
        $this->createSocket();
63
    }
64 32
65
    protected function setConnectTimeout(float $timeout = null): void
66 32
    {
67 1
        if ($timeout === null) {
68 1
            list($host) = explode(':', $this->address);
69 1
            if (array_key_exists("HOST_$host", self::DEFAULT_CONNECT_TIMEOUTS)) {
70 1
                $timeout = self::DEFAULT_CONNECT_TIMEOUTS["HOST_$host"];
71
            } else {
72
                $timeout = self::DEFAULT_CONNECT_TIMEOUTS['DEFAULT'];
73 31
            }
74 31
        }
75
        $this->connectTimeout = $timeout;
76 31
    }
77
78 31
    /**
79
     * @throws InvalidArgumentException when getting an unsupported transport
80
     */
81
    protected function setTransport(string $transport): void
82
    {
83
        if (!in_array($transport, self::REGISTERED_TRANSPORTS, true)) {
84 26
            throw new InvalidArgumentException(sprintf(
85
                'Unsupported transport "%s" given (supported: %s)',
86 26
                $transport,
87
                implode(',', array_keys(self::REGISTERED_TRANSPORTS))
88
            ));
89 31
        }
90
        $this->transport = $transport;
91 31
    }
92
93
    public function getTransport(): string
94
    {
95
        return $this->transport;
96
    }
97 31
98
    public function getConnectTimeout(): float
99 31
    {
100 31
        return $this->connectTimeout;
101 31
    }
102 31
103 31
    /**
104 31
     * @return resource php socket
105 31
     */
106
    public function getSocket()
107 31
    {
108 28
        return $this->socket;
109
    }
110
111
    public function getStreamAddress(): string
112
    {
113
        return sprintf('%s://%s', $this->getTransport(), $this->address);
114
    }
115
116
    /**
117 31
     * Whether the connection is persistent or not.
118
     *
119 31
     * @return bool
120 3
     */
121 3
    public function isPersistent(): bool
122 3
    {
123 3
        return $this->persistent;
124 3
    }
125
126 3
    /**
127
     * @throws ConnectionException
128 28
     */
129
    protected function createSocket(): void
130 31
    {
131
        $this->socket = @stream_socket_client(
0 ignored issues
show
Documentation Bug introduced by
It seems like @stream_socket_client($t...is->getStreamContext()) can also be of type false. However, the property $socket is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
132 31
            $this->getStreamAddress(),
133
            $errno,
134
            $errstr,
135
            $this->connectTimeout,
136
            $this->getStreamFlags(),
137
            $this->getStreamContext()
138 31
        );
139
        $this->checkSocket($this->socket, $errno, $errstr);
140 31
    }
141
142
    /**
143
     * @param resource|false $socket
144
     * @param int|null       $errno
145
     * @param string|null    $errstr
146
     *
147
     * @throws ConnectionException
148
     */
149
    protected function checkSocket($socket, int $errno = null, string $errstr = null): void
150
    {
151
        if ($socket === false || !is_resource($socket)) {
152
            $msg = sprintf(
153
                "Could not connect to the php-java-bridge server '%s'. Please start it. (err: %s, %s)",
154
                $this->address,
155
                $errno ?? 0,
156
                $errstr ?? 'Empty errstr returned'
157
            );
158
            throw new ConnectionException($msg);
159
        }
160
    }
161
162
    protected function getStreamFlags(): int
163
    {
164
        return $this->persistent ? STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT : STREAM_CLIENT_CONNECT;
165
    }
166
167
    /**
168
     * @return resource
169
     */
170
    protected function getStreamContext()
171
    {
172
        return stream_context_create($this->streamContext);
173
    }
174
}
175