Completed
Pull Request — master (#262)
by Vasily
04:35
created

Pool::getInstance()   D

Complexity

Conditions 9
Paths 24

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 9
eloc 20
c 4
b 1
f 0
nc 24
nop 2
dl 0
loc 25
rs 4.909
1
<?php
2
namespace PHPDaemon\Network;
3
4
use PHPDaemon\BoundSocket;
5
use PHPDaemon\Config;
6
use PHPDaemon\Core\Daemon;
7
use PHPDaemon\Core\EventLoop;
8
use PHPDaemon\Structures\ObjectStorage;
9
use PHPDaemon\Thread;
10
use PHPDaemon\Traits\EventLoopContainer;
11
12
/**
13
 * Pool of connections
14
 * @package PHPDaemon\Network
15
 * @author  Vasily Zorin <[email protected]>
16
 */
17
abstract class Pool extends ObjectStorage
18
{
19
20
    use EventLoopContainer;
21
22
    /**
23
     * @var string Default connection class
24
     */
25
    public $connectionClass;
26
27
    /**
28
     * @var string Name
29
     */
30
    public $name;
31
32
    /**
33
     * @var \PHPDaemon\Config\Section Configuration
34
     */
35
    public $config;
36
37
    /**
38
     * @var ConnectionPool[] Instances storage
39
     */
40
    protected static $instances = [];
41
42
    /**
43
     * @var integer Max concurrency
44
     */
45
    public $maxConcurrency = 0;
46
47
    /**
48
     * @var integer Max allowed packet
49
     */
50
    public $maxAllowedPacket = 0;
51
52
    /**
53
     * @var boolean Is finished?
54
     */
55
    protected $finished = false;
56
57
    /**
58
     * @var boolean Is enabled?
59
     */
60
    protected $enabled = false;
61
62
    /**
63
     * @var boolean Is overloaded?
64
     */
65
    protected $overload = false;
66
67
    /**
68
     * @var object|null Application instance object
69
     */
70
    public $appInstance;
71
72
    /**
73
     * Constructor
74
     * @param array $config Config variables
75
     * @param boolean $init
76
     */
77
    public function __construct($config = [], $init = true)
78
    {
79
        $this->config = $config;
0 ignored issues
show
Documentation Bug introduced by
It seems like $config of type array is incompatible with the declared type object<PHPDaemon\Config\Section> of property $config.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
80
        $this->onConfigUpdated();
81
        if ($this->connectionClass === null) {
82
            $e = explode('\\', get_class($this));
83
            $e[sizeof($e) - 1] = 'Connection';
84
            $this->connectionClass = '\\' . implode('\\', $e);
85
        }
86
        if ($this->eventLoop === null) {
87
            $this->eventLoop = EventLoop::$instance;
88
        }
89
        if ($init) {
90
            $this->init();
91
        }
92
    }
93
94
95
    /**
96
     * Init
97
     * @return void
98
     */
99
    protected function init()
100
    {
101
    }
102
103
    /**
104
     * Called when the worker is ready to go
105
     * @return void
106
     */
107
    public function onReady()
108
    {
109
        $this->enable();
110
    }
111
112
    /**
113
     * Called when worker is going to update configuration
114
     * @return void
115
     */
116
    public function onConfigUpdated()
117
    {
118
        if (Daemon::$process instanceof Thread\Worker) {
119
            if ($this->config === null) {
120
                $this->disable();
121
            } else {
122
                $this->enable();
123
            }
124
        }
125
        if ($defaults = $this->getConfigDefaults()) {
126
            $this->config->imposeDefault($defaults);
0 ignored issues
show
Documentation introduced by
$defaults is of type boolean, but the function expects a array.

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...
127
        }
128
        $this->applyConfig();
129
    }
130
131
    /**
132
     * Applies config
133
     * @return void
134
     */
135
    protected function applyConfig()
136
    {
137
        foreach ($this->config as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $this->config of type object<PHPDaemon\Config\Section> is not traversable.
Loading history...
138
            if (is_object($v) && $v instanceof Config\Entry\Generic) {
139
                $v = $v->getValue();
140
            }
141
            $k = strtolower($k);
142
            if ($k === 'connectionclass') {
143
                $this->connectionClass = $v;
144
            } elseif ($k === 'name') {
145
                $this->name = $v;
146
            } elseif ($k === 'maxallowedpacket') {
147
                $this->maxAllowedPacket = (int)$v;
148
            } elseif ($k === 'maxconcurrency') {
149
                $this->maxConcurrency = (int)$v;
150
            }
151
        }
152
    }
153
154
    /**
155
     * Setting default config options
156
     * @return boolean
157
     */
158
    protected function getConfigDefaults()
159
    {
160
        return false;
161
    }
162
163
    /**
164
     * Returns instance object
165
     * @param  string $arg name / array config / ConfigSection
166
     * @param  boolean $spawn Spawn? Default is true
167
     * @return this
168
     */
169
    public static function getInstance($arg = '', $spawn = true)
170
    {
171
        if ($arg === 'default') {
172
            $arg = '';
173
        }
174
        $class = get_called_class();
175
        if (is_string($arg)) {
176
            $key = $class . ':' . $arg;
177
            if (isset(self::$instances[$key])) {
178
                return self::$instances[$key];
179
            } elseif (!$spawn) {
180
                return false;
181
            }
182
            $k = '\PHPDaemon\Core\Pool:\\' . $class . ($arg !== '' ? ':' . $arg : '');
183
            $config = (isset(Daemon::$config->{$k}) && Daemon::$config->{$k} instanceof Config\Section) ? Daemon::$config->{$k} : new Config\Section;
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 149 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
184
            $obj = self::$instances[$key] = new $class($config);
185
            $obj->name = $arg;
186
        } elseif ($arg instanceof Config\Section) {
187
            $obj = new static($arg);
188
        } else {
189
            $obj = new static(new Config\Section($arg));
0 ignored issues
show
Documentation introduced by
new \PHPDaemon\Config\Section($arg) is of type object<PHPDaemon\Config\Section>, but the function expects a array.

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...
190
        }
191
        $obj->eventLoop = EventLoop::$instance;
192
        return $obj;
193
    }
194
195
    /**
196
     * Sets default connection class
197
     * @param  string $class Connection class name
198
     * @return void
199
     */
200
    public function setConnectionClass($class)
201
    {
202
        $this->connectionClass = $class;
203
    }
204
205
    /**
206
     * Enable socket events
207
     * @return void
208
     */
209
    public function enable()
210
    {
211
        if ($this->enabled) {
212
            return;
213
        }
214
        $this->enabled = true;
215
        $this->onEnable();
216
    }
217
218
    /**
219
     * Disable all events of sockets
220
     * @return void
221
     */
222
    public function disable()
223
    {
224
        if (!$this->enabled) {
225
            return;
226
        }
227
        $this->enabled = false;
228
        $this->onDisable();
229
    }
230
231
    /**
232
     * Called when ConnectionPool is now enabled
233
     * @return void
234
     */
235
    protected function onEnable()
236
    {
237
    }
238
239
    /**
240
     * Called when ConnectionPool is now disabled
241
     * @return void
242
     */
243
    protected function onDisable()
244
    {
245
    }
246
247
    /**
248
     * Called when application instance is going to shutdown
249
     * @param  boolean $graceful
250
     * @return boolean Ready to shutdown?
251
     */
252
    public function onShutdown($graceful = false)
253
    {
254
        return $this->finish($graceful);
255
    }
256
257
    /**
258
     * Called when ConnectionPool is finished
259
     * @return void
260
     */
261
    protected function onFinish()
262
    {
263
    }
264
265
    /**
266
     * Finishes ConnectionPool
267
     * @return boolean Success
268
     */
269
    public function finish($graceful = false)
270
    {
271
        $this->disable();
272
273
        if (!$this->finished) {
274
            $this->finished = true;
275
            $this->onFinish();
276
        }
277
278
        $result = true;
279
280
        foreach ($this as $conn) {
281
            if ($graceful) {
282
                if (!$conn->gracefulShutdown()) {
283
                    $result = false;
284
                }
285
            } else {
286
                $conn->finish();
287
            }
288
        }
289
290
        return $result;
291
    }
292
293
    /**
294
     * Attach Connection
295
     * @param  object $conn Connection
296
     * @param  mixed $inf Info
297
     * @return void
298
     */
299 View Code Duplication
    public function attach($conn, $inf = null)
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...
300
    {
301
        parent::attach($conn, $inf);
302
        if ($this->maxConcurrency && !$this->overload) {
303
            if ($this->count() >= $this->maxConcurrency) {
304
                $this->overload = true;
305
                $this->disable();
306
                return;
307
            }
308
        }
309
    }
310
311
    /**
312
     * Detach Connection
313
     * @param  object $conn Connection
314
     * @return void
315
     */
316 View Code Duplication
    public function detach($conn)
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...
317
    {
318
        parent::detach($conn);
319
        if ($this->overload) {
320
            if (!$this->maxConcurrency || ($this->count() < $this->maxConcurrency)) {
321
                $this->overload = false;
322
                $this->enable();
323
            }
324
        }
325
    }
326
327
    /**
328
     * Establish a connection with remote peer
329
     * @param  string $url URL
330
     * @param  callback $cb Callback
331
     * @param  string $class Optional. Connection class name
0 ignored issues
show
Documentation introduced by
Should the type for parameter $class not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
332
     * @return integer         Connection's ID. Boolean false when failed
0 ignored issues
show
Documentation introduced by
Should the return type not be object?

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...
333
     */
334
    public function connect($url, $cb, $class = null)
335
    {
336
        if ($class === null) {
337
            $class = $this->connectionClass;
338
        }
339
        $conn = new $class(null, $this);
340
        $conn->connect($url, $cb);
341
        return $conn;
342
    }
343
}
344