Completed
Push — EventLoopContainer ( c9a84d )
by Vasily
04:35
created

Pool::getInstance()   D

Complexity

Conditions 9
Paths 24

Size

Total Lines 26
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 9
dl 0
loc 26
rs 4.909
c 3
b 1
f 0
eloc 21
nc 24
nop 2
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 ($init) {
87
            $this->init();
88
        }
89
    }
90
91
92
    /**
93
     * Init
94
     * @return void
95
     */
96
    protected function init()
97
    {
98
    }
99
100
    /**
101
     * Called when the worker is ready to go
102
     * @return void
103
     */
104
    public function onReady()
105
    {
106
        $this->enable();
107
    }
108
109
    /**
110
     * Called when worker is going to update configuration
111
     * @return void
112
     */
113
    public function onConfigUpdated()
114
    {
115
        if (Daemon::$process instanceof Thread\Worker) {
116
            if ($this->config === null) {
117
                $this->disable();
118
            } else {
119
                $this->enable();
120
            }
121
        }
122
        if ($defaults = $this->getConfigDefaults()) {
123
            $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...
124
        }
125
        $this->applyConfig();
126
    }
127
128
    /**
129
     * Applies config
130
     * @return void
131
     */
132
    protected function applyConfig()
133
    {
134
        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...
135
            if (is_object($v) && $v instanceof Config\Entry\Generic) {
136
                $v = $v->getValue();
137
            }
138
            $k = strtolower($k);
139
            if ($k === 'connectionclass') {
140
                $this->connectionClass = $v;
141
            } elseif ($k === 'name') {
142
                $this->name = $v;
143
            } elseif ($k === 'maxallowedpacket') {
144
                $this->maxAllowedPacket = (int)$v;
145
            } elseif ($k === 'maxconcurrency') {
146
                $this->maxConcurrency = (int)$v;
147
            }
148
        }
149
    }
150
151
    /**
152
     * Setting default config options
153
     * @return boolean
154
     */
155
    protected function getConfigDefaults()
156
    {
157
        return false;
158
    }
159
160
    /**
161
     * Returns instance object
162
     * @param  string $arg name / array config / ConfigSection
163
     * @param  boolean $spawn Spawn? Default is true
164
     * @return this
165
     */
166
    public static function getInstance($arg = '', $spawn = true)
167
    {
168
        if ($arg === 'default') {
169
            $arg = '';
170
        }
171
        $class = get_called_class();
172
        if (is_string($arg)) {
173
            $key = $class . ':' . $arg;
174
            if (isset(self::$instances[$key])) {
175
                return self::$instances[$key];
176
            } elseif (!$spawn) {
177
                return false;
178
            }
179
            $k = '\PHPDaemon\Core\Pool:\\' . $class . ($arg !== '' ? ':' . $arg : '');
180
            $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...
181
            $obj = self::$instances[$key] = new $class($config);
182
            $obj->name = $arg;
183
        } elseif ($arg instanceof Config\Section) {
184
            $obj = new static($arg);
185
        } else {
186
            $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...
187
        }
188
        $obj->eventLoop = EventLoop::$instance;
189
        var_dump(['iostream0 pool' => md5(spl_object_hash($obj)), 'eventLoop' => $obj->eventLoop]);
0 ignored issues
show
Security Debugging Code introduced by
var_dump(array('iostream...' => $obj->eventLoop)); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
190
        return $obj;
191
    }
192
193
    /**
194
     * Sets default connection class
195
     * @param  string $class Connection class name
196
     * @return void
197
     */
198
    public function setConnectionClass($class)
199
    {
200
        $this->connectionClass = $class;
201
    }
202
203
    /**
204
     * Enable socket events
205
     * @return void
206
     */
207
    public function enable()
208
    {
209
        if ($this->enabled) {
210
            return;
211
        }
212
        $this->enabled = true;
213
        $this->onEnable();
214
    }
215
216
    /**
217
     * Disable all events of sockets
218
     * @return void
219
     */
220
    public function disable()
221
    {
222
        if (!$this->enabled) {
223
            return;
224
        }
225
        $this->enabled = false;
226
        $this->onDisable();
227
    }
228
229
    /**
230
     * Called when ConnectionPool is now enabled
231
     * @return void
232
     */
233
    protected function onEnable()
234
    {
235
    }
236
237
    /**
238
     * Called when ConnectionPool is now disabled
239
     * @return void
240
     */
241
    protected function onDisable()
242
    {
243
    }
244
245
    /**
246
     * Called when application instance is going to shutdown
247
     * @param  boolean $graceful
248
     * @return boolean Ready to shutdown?
249
     */
250
    public function onShutdown($graceful = false)
251
    {
252
        return $this->finish($graceful);
253
    }
254
255
    /**
256
     * Called when ConnectionPool is finished
257
     * @return void
258
     */
259
    protected function onFinish()
260
    {
261
    }
262
263
    /**
264
     * Finishes ConnectionPool
265
     * @return boolean Success
266
     */
267
    public function finish($graceful = false)
268
    {
269
        $this->disable();
270
271
        if (!$this->finished) {
272
            $this->finished = true;
273
            $this->onFinish();
274
        }
275
276
        $result = true;
277
278
        foreach ($this as $conn) {
279
            if ($graceful) {
280
                if (!$conn->gracefulShutdown()) {
281
                    $result = false;
282
                }
283
            } else {
284
                $conn->finish();
285
            }
286
        }
287
288
        return $result;
289
    }
290
291
    /**
292
     * Attach Connection
293
     * @param  object $conn Connection
294
     * @param  mixed $inf Info
295
     * @return void
296
     */
297 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...
298
    {
299
        parent::attach($conn, $inf);
300
        if ($this->maxConcurrency && !$this->overload) {
301
            if ($this->count() >= $this->maxConcurrency) {
302
                $this->overload = true;
303
                $this->disable();
304
                return;
305
            }
306
        }
307
    }
308
309
    /**
310
     * Detach Connection
311
     * @param  object $conn Connection
312
     * @return void
313
     */
314 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...
315
    {
316
        parent::detach($conn);
317
        if ($this->overload) {
318
            if (!$this->maxConcurrency || ($this->count() < $this->maxConcurrency)) {
319
                $this->overload = false;
320
                $this->enable();
321
            }
322
        }
323
    }
324
325
    /**
326
     * Establish a connection with remote peer
327
     * @param  string $url URL
328
     * @param  callback $cb Callback
329
     * @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...
330
     * @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...
331
     */
332
    public function connect($url, $cb, $class = null)
333
    {
334
        if ($class === null) {
335
            $class = $this->connectionClass;
336
        }
337
        $conn = new $class(null, $this);
338
        $conn->connect($url, $cb);
339
        return $conn;
340
    }
341
}
342