Completed
Push — master ( dd5d5f...c73d62 )
by lan tian
8s
created

Sms   D

Complexity

Total Complexity 131

Size/Duplication

Total Lines 821
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 4

Test Coverage

Coverage 93.38%

Importance

Changes 37
Bugs 8 Features 8
Metric Value
wmc 131
c 37
b 8
f 8
lcom 2
cbo 4
dl 0
loc 821
ccs 296
cts 317
cp 0.9338
rs 4.4444

41 Methods

Rating   Name   Duplication   Size   Complexity  
A voice() 0 7 1
A generatorAgentsName() 0 8 4
A getEnableAgents() 0 4 1
A __construct() 0 6 2
B make() 0 15 6
B queue() 0 16 5
A to() 0 6 1
A content() 0 6 1
B template() 0 15 7
A data() 0 6 1
A agent() 0 6 1
B send() 0 32 4
A push() 0 15 3
A getData() 0 4 1
A bootstrap() 0 11 3
A generatorTask() 0 8 2
A configuration() 0 7 1
B generatorAgentsConfig() 0 13 6
A configValidator() 0 6 2
C createDrivers() 0 34 7
A parseAgentArrayOptions() 0 10 1
B pullAgentOptionByName() 0 10 5
A getAgentConfigData() 0 5 2
B getSmsAgent() 0 21 8
A validator() 0 8 2
B enable() 0 14 12
B agents() 0 13 6
A getAgentsConfig() 0 4 1
A cleanEnableAgents() 0 4 1
A cleanAgentsConfig() 0 4 1
B __callStatic() 0 19 8
A __call() 0 8 2
A __sleep() 0 8 1
A __wakeup() 0 8 1
A getSerializer() 0 8 2
A serializeHandlers() 0 17 4
A reinstallHandlers() 0 13 4
A serializeEnableAgents() 0 12 3
A unserializeEnableAgents() 0 11 3
A serializeClosureAndReplace() 0 7 3
A unserializeToClosureAndReplace() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Sms often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Sms, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Toplan\PhpSms;
4
5
use SuperClosure\Serializer;
6
use Toplan\TaskBalance\Balancer;
7
8
/**
9
 * Class Sms
10
 */
11
class Sms
12
{
13
    /**
14
     * sms send task name
15
     */
16
    const TASK = 'PhpSms';
17
18
    /**
19
     * agents instance
20
     */
21
    protected static $agents = [];
22
23
    /**
24
     * agents`s name
25
     *
26
     * @var
27
     */
28
    protected static $agentsName = [];
29
30
    /**
31
     * agents`s config
32
     *
33
     * @var
34
     */
35
    protected static $agentsConfig = [];
36
37
    /**
38
     * whether to enable queue
39
     *
40
     * @var bool
41
     */
42
    protected static $enableQueue = false;
43
44
    /**
45
     * queue work
46
     *
47
     * @var \Closure
48
     */
49
    protected static $howToUseQueue = null;
50
51
    /**
52
     * sms already pushed to queue
53
     *
54
     * @var bool
55
     */
56
    protected $pushedToQueue = false;
57
58
    /**
59
     * hook handlers
60
     *
61
     * @var array
62
     */
63
    protected static $enableHooks = [
64
        'beforeRun',
65
        'beforeDriverRun',
66
        'afterDriverRun',
67
        'afterRun',
68
    ];
69
70
    /**
71
     * sms data
72
     *
73
     * @var array
74
     */
75
    protected $smsData = [
76
        'to'           => null,
77
        'templates'    => [],
78
        'content'      => '',
79
        'templateData' => [],
80
        'voiceCode'    => null,
81
    ];
82
83
    /**
84
     * first agent for send sms/voice verify
85
     *
86
     * @var string
87
     */
88
    protected $firstAgent = null;
89
90
    /**
91
     * a instance of class 'SuperClosure\Serializer'
92
     *
93
     * @var Serializer
94
     */
95
    protected static $serializer = null;
96
97
    /**
98
     * store the static properties of Sms class when serialize a instance
99
     *
100
     * @var array
101
     */
102
    protected $_status_before_enqueue_ = [];
103
104
    /**
105
     * construct
106
     *
107
     * @param bool $autoBoot
108
     */
109 9
    public function __construct($autoBoot = true)
110
    {
111 9
        if ($autoBoot) {
112 9
            self::bootstrap();
113 6
        }
114 9
    }
115
116
    /**
117
     * create sms instance and set templates
118
     *
119
     * @param mixed $agentName
120
     * @param mixed $tempId
121
     *
122
     * @return Sms
123
     */
124 3
    public static function make($agentName = null, $tempId = null)
125
    {
126 3
        $sms = new self();
127 3
        if (is_array($agentName)) {
128
            $sms->template($agentName);
129 3
        } elseif ($agentName && is_string($agentName)) {
130
            if ($tempId === null) {
131
                $sms->content($agentName);
132
            } elseif (is_string("$tempId")) {
133
                $sms->template($agentName, $tempId);
134
            }
135
        }
136
137 3
        return $sms;
138
    }
139
140
    /**
141
     * send voice verify
142
     *
143
     * @param $code
144
     *
145
     * @return Sms
146
     */
147 3
    public static function voice($code)
148
    {
149 3
        $sms = new self();
150 3
        $sms->smsData['voiceCode'] = $code;
151
152 3
        return $sms;
153
    }
154
155
    /**
156
     * set how to use queue.
157
     *
158
     * @param $enable
159
     * @param $handler
160
     *
161
     * @return bool
162
     */
163 3
    public static function queue($enable = null, $handler = null)
164
    {
165 3
        if ($enable === null && $handler === null) {
166 3
            return self::$enableQueue;
167
        }
168 3
        if (is_callable($enable)) {
169 3
            $handler = $enable;
170 3
            $enable = true;
171 2
        }
172 3
        self::$enableQueue = (bool) $enable;
173 3
        if (is_callable($handler)) {
174 3
            self::$howToUseQueue = $handler;
0 ignored issues
show
Documentation Bug introduced by
It seems like $handler of type callable is incompatible with the declared type object<Closure> of property $howToUseQueue.

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...
175 2
        }
176
177 3
        return self::$enableQueue;
178
    }
179
180
    /**
181
     * set the mobile number
182
     *
183
     * @param $mobile
184
     *
185
     * @return $this
186
     */
187 6
    public function to($mobile)
188
    {
189 6
        $this->smsData['to'] = $mobile;
190
191 6
        return $this;
192
    }
193
194
    /**
195
     * set content for content sms
196
     *
197
     * @param $content
198
     *
199
     * @return $this
200
     */
201 3
    public function content($content)
202
    {
203 3
        $this->smsData['content'] = trim((string) $content);
204
205 3
        return $this;
206
    }
207
208
    /**
209
     * set template id for template sms
210
     *
211
     * @param $agentName
212
     * @param $tempId
213
     *
214
     * @return $this
215
     */
216 3
    public function template($agentName, $tempId = null)
217
    {
218 3
        if (is_array($agentName)) {
219 3
            foreach ($agentName as $k => $v) {
220 3
                $this->template($k, $v);
221 2
            }
222 3
        } elseif ($agentName && $tempId) {
223 3
            if (!isset($this->smsData['templates']) || !is_array($this->smsData['templates'])) {
224
                $this->smsData['templates'] = [];
225
            }
226 3
            $this->smsData['templates']["$agentName"] = $tempId;
227 2
        }
228
229 3
        return $this;
230
    }
231
232
    /**
233
     * set data for template sms
234
     *
235
     * @param array $data
236
     *
237
     * @return $this
238
     */
239 3
    public function data(array $data)
240
    {
241 3
        $this->smsData['templateData'] = $data;
242
243 3
        return $this;
244
    }
245
246
    /**
247
     * set the first agent
248
     *
249
     * @param $name
250
     *
251
     * @return $this
252
     */
253 3
    public function agent($name)
254
    {
255 3
        $this->firstAgent = (string) $name;
256
257 3
        return $this;
258
    }
259
260
    /**
261
     * start send
262
     *
263
     * @param bool $immediately
264
     *
265
     * @return mixed
266
     */
267 18
    public function send($immediately = false)
268
    {
269 18
        $this->validator();
270
271
        // if disable push to queue,
272
        // send the sms immediately.
273 18
        if (!self::$enableQueue) {
274 15
            $immediately = true;
275 10
        }
276
277
        // whatever 'PhpSms' whether to enable or disable push to queue,
278
        // if you are already pushed sms instance to queue,
279
        // you can recall the method `send()` in queue job without `true` parameter.
280
        //
281
        // So this mechanism in order to make you convenient use the method `send()` in queue system.
282 18
        if ($this->pushedToQueue) {
283 3
            $immediately = true;
284 2
        }
285
286
        // whether to send sms immediately,
287
        // or push it to queue.
288 18
        if ($immediately) {
289 18
            $result = Balancer::run(self::TASK, [
290 18
                'data'   => $this->getData(),
291 18
                'driver' => $this->firstAgent,
292 12
            ]);
293 12
        } else {
294 3
            $result = $this->push();
295
        }
296
297 18
        return $result;
298
    }
299
300
    /**
301
     * push sms send task to queue
302
     *
303
     * @throws \Exception | PhpSmsException
304
     *
305
     * @return mixed
306
     */
307 3
    protected function push()
308
    {
309 3
        if (is_callable(self::$howToUseQueue)) {
310
            try {
311 3
                $this->pushedToQueue = true;
312
313 3
                return call_user_func_array(self::$howToUseQueue, [$this, $this->smsData]);
314
            } catch (\Exception $e) {
315
                $this->pushedToQueue = false;
316
                throw $e;
317
            }
318
        } else {
319
            throw new PhpSmsException('Please define how to use queue by method `queue($enable, $handler)`');
320
        }
321
    }
322
323
    /**
324
     * get sms data
325
     *
326
     * @return array
327
     */
328 36
    public function getData()
329
    {
330 36
        return $this->smsData;
331
    }
332
333
    /**
334
     * bootstrap
335
     *
336
     * @param bool $force
337
     */
338 12
    public static function bootstrap($force = false)
339
    {
340 12
        if ((bool) $force) {
341 3
            Balancer::destroy(self::TASK);
342 2
        }
343 12
        $task = self::generatorTask();
344 12
        if (!count($task->drivers)) {
345 6
            self::configuration();
346 6
            self::createDrivers($task);
347 4
        }
348 12
    }
349
350
    /**
351
     * generator a sms send task
352
     *
353
     * @return object
354
     */
355 21
    public static function generatorTask()
356
    {
357 21
        if (!Balancer::hasTask(self::TASK)) {
358 6
            Balancer::task(self::TASK);
359 4
        }
360
361 21
        return Balancer::getTask(self::TASK);
362
    }
363
364
    /**
365
     * configuration
366
     */
367 6
    protected static function configuration()
368
    {
369 6
        $config = [];
370 6
        self::generatorAgentsName($config);
371 6
        self::generatorAgentsConfig($config);
372 6
        self::configValidator();
373 6
    }
374
375
    /**
376
     * generate enabled agents name
377
     *
378
     * @param array $config
379
     */
380 6
    protected static function generatorAgentsName(&$config)
381
    {
382 6
        if (empty(self::$agentsName)) {
383 3
            $config = $config ?: include __DIR__ . '/../config/phpsms.php';
384 3
            $enableAgents = isset($config['enable']) ? $config['enable'] : null;
385 3
            self::enable($enableAgents);
386 2
        }
387 6
    }
388
389
    /**
390
     * generator agents config
391
     *
392
     * @param array $config
393
     */
394 6
    protected static function generatorAgentsConfig(&$config)
395
    {
396 6
        $diff = array_diff_key(self::$agentsName, self::$agentsConfig);
397 6
        $diff = array_keys($diff);
398 6
        if (count($diff)) {
399 6
            $config = $config ?: include __DIR__ . '/../config/phpsms.php';
400 6
            $agentsConfig = isset($config['agents']) ? $config['agents'] : [];
401 6
            foreach ($diff as $name) {
402 6
                $agentConfig = isset($agentsConfig[$name]) ? $agentsConfig[$name] : [];
403 6
                self::agents($name, $agentConfig);
404 4
            }
405 4
        }
406 6
    }
407
408
    /**
409
     * config value validator
410
     *
411
     * @throws PhpSmsException
412
     */
413 6
    protected static function configValidator()
414
    {
415 6
        if (!count(self::$agentsName)) {
416
            throw new PhpSmsException('Please set at least one enable agent in config file(config/phpsms.php) or use method enable()');
417
        }
418 6
    }
419
420
    /**
421
     * create drivers for sms send task
422
     *
423
     * @param $task
424
     */
425 18
    protected static function createDrivers($task)
426
    {
427 6
        foreach (self::$agentsName as $name => $options) {
428
            //获取代理器配置
429 6
            $configData = self::getAgentConfigData($name);
430
            //解析代理器数组模式的调度配置
431 6
            if (is_array($options)) {
432 3
                $data = self::parseAgentArrayOptions($options);
433 3
                $configData = array_merge($configData, $data);
434 3
                $options = $data['driverOpts'];
435 2
            }
436
            //创建任务驱动器
437 6
            $task->driver("$name $options")->data($configData)
438 18
                 ->work(function ($driver) {
439 18
                     $configData = $driver->getDriverData();
440 18
                     $agent = self::getSmsAgent($driver->name, $configData);
441 18
                     $smsData = $driver->getTaskData();
442 18
                     extract($smsData);
443 18
                     if (isset($smsData['voiceCode']) && $smsData['voiceCode']) {
444
                         $agent->voiceVerify($to, $voiceCode);
445
                     } else {
446 18
                         $template = isset($templates[$driver->name]) ? $templates[$driver->name] : 0;
447 18
                         $agent->sendSms($template, $to, $templateData, $content);
448
                     }
449 18
                     $result = $agent->result();
450 18
                     if ($result['success']) {
451 18
                         $driver->success();
452 12
                     }
453 18
                     unset($result['success']);
454
455 18
                     return $result;
456 6
                 });
457 4
        }
458 6
    }
459
460
    /**
461
     * 解析可用代理器的数组模式的调度配置
462
     *
463
     * @param array $options
464
     *
465
     * @return array
466
     */
467 3
    protected static function parseAgentArrayOptions(array $options)
468
    {
469 3
        $agentClass = self::pullAgentOptionByName($options, 'agentClass');
470 3
        $sendSms = self::pullAgentOptionByName($options, 'sendSms');
471 3
        $voiceVerify = self::pullAgentOptionByName($options, 'voiceVerify');
472 3
        $backup = self::pullAgentOptionByName($options, 'backup');
473 3
        $driverOpts = implode(' ', array_values($options)) . " $backup";
474
475 3
        return compact('agentClass', 'sendSms', 'voiceVerify', 'driverOpts');
476
    }
477
478
    /**
479
     * 从调度配置中拉取指定数据
480
     *
481
     * @param array  $options
482
     * @param string $name
483
     *
484
     * @return null|string
485
     */
486 3
    protected static function pullAgentOptionByName(array &$options, $name)
487
    {
488 3
        $value = isset($options[$name]) ? $options[$name] : null;
489 3
        if ($name === 'backup') {
490 3
            $value = isset($options[$name]) ? ($options[$name] ? 'backup' : '') : '';
491 2
        }
492 3
        unset($options[$name]);
493
494 3
        return $value;
495
    }
496
497
    /**
498
     * get agent config data by name
499
     *
500
     * @param $name
501
     *
502
     * @return array
503
     */
504 6
    protected static function getAgentConfigData($name)
505
    {
506 6
        return isset(self::$agentsConfig[$name]) ?
507 6
               (array) self::$agentsConfig[$name] : [];
508
    }
509
510
    /**
511
     * get a sms agent instance,
512
     * if null, will create a new agent instance
513
     *
514
     * @param       $name
515
     * @param array $configData
516
     *
517
     * @throws PhpSmsException
518
     *
519
     * @return mixed
520
     */
521 21
    public static function getSmsAgent($name, array $configData)
522
    {
523 21
        if (!isset(self::$agents[$name])) {
524 6
            $configData['name'] = $name;
525 6
            $className = isset($configData['agentClass']) ? $configData['agentClass'] : ('Toplan\\PhpSms\\' . $name . 'Agent');
526 6
            if ((isset($configData['sendSms']) && is_callable($configData['sendSms'])) ||
527 6
                (isset($configData['voiceVerify']) && is_callable($configData['voiceVerify']))) {
528
                //创建寄生代理器
529 3
                $configData['agentClass'] = '';
530 3
                self::$agents[$name] = new ParasiticAgent($configData);
531 5
            } elseif (class_exists($className)) {
532
                //创建新代理器
533 3
                self::$agents[$name] = new $className($configData);
534 2
            } else {
535
                //无代理器可用
536
                throw new PhpSmsException("Do not support [$name] agent.");
537
            }
538 4
        }
539
540 21
        return self::$agents[$name];
541
    }
542
543
    /**
544
     * validate
545
     *
546
     * @throws PhpSmsException
547
     */
548 21
    protected function validator()
549
    {
550 21
        if (!$this->smsData['to']) {
551
            throw new PhpSmsException('Please set send sms(or voice verify) to who use `to()` method.');
552
        }
553
554 21
        return true;
555
    }
556
557
    /**
558
     * set enable agents
559
     *
560
     * @param      $agentName
561
     * @param null $options
562
     */
563 6
    public static function enable($agentName, $options = null)
564
    {
565 6
        if (is_array($agentName)) {
566 6
            foreach ($agentName as $name => $opt) {
567 6
                self::enable($name, $opt);
568 4
            }
569 6
        } elseif ($agentName && is_string($agentName) && $options !== null) {
570 3
            self::$agentsName["$agentName"] = is_array($options) ? $options : "$options";
571 6
        } elseif (is_int($agentName) && !is_array($options) && "$options") {
572 3
            self::$agentsName["$options"] = '1';
573 5
        } elseif ($agentName && $options === null) {
574 3
            self::$agentsName["$agentName"] = '1';
575 2
        }
576 6
    }
577
578
    /**
579
     * set config for available agents
580
     *
581
     * @param       $agentName
582
     * @param array $config
583
     *
584
     * @throws PhpSmsException
585
     */
586 9
    public static function agents($agentName, array $config = [])
587
    {
588 9
        if (is_array($agentName)) {
589 3
            foreach ($agentName as $name => $conf) {
590 3
                self::agents($name, $conf);
591 2
            }
592 9
        } elseif ($agentName && is_array($config)) {
593 9
            if (preg_match('/^[0-9]+$/', $agentName)) {
594
                throw new PhpSmsException("Agent name [$agentName] must be string, could not be a pure digital");
595
            }
596 9
            self::$agentsConfig["$agentName"] = $config;
597 6
        }
598 9
    }
599
600
    /**
601
     * get enable agents
602
     *
603
     * @return array
604
     */
605 12
    public static function getEnableAgents()
606
    {
607 12
        return self::$agentsName;
608
    }
609
610
    /**
611
     * get agents config info
612
     *
613
     * @return array
614
     */
615 12
    public static function getAgentsConfig()
616
    {
617 12
        return self::$agentsConfig;
618
    }
619
620
    /**
621
     * tear down enable agents
622
     */
623 6
    public static function cleanEnableAgents()
624
    {
625 6
        self::$agentsName = [];
626 6
    }
627
628
    /**
629
     * tear down agents config
630
     */
631 3
    public static function cleanAgentsConfig()
632
    {
633 3
        self::$agentsConfig = [];
634 3
    }
635
636
    /**
637
     * overload static method
638
     *
639
     * @param $name
640
     * @param $args
641
     *
642
     * @throws PhpSmsException
643
     */
644 9
    public static function __callStatic($name, $args)
645
    {
646 9
        $name = $name === 'beforeSend' ? 'beforeRun' : $name;
647 9
        $name = $name === 'afterSend' ? 'afterRun' : $name;
648 9
        $name = $name === 'beforeAgentSend' ? 'beforeDriverRun' : $name;
649 9
        $name = $name === 'afterAgentSend' ? 'afterDriverRun' : $name;
650 9
        if (in_array($name, self::$enableHooks)) {
651 9
            $handler = $args[0];
652 9
            $override = isset($args[1]) ? (bool) $args[1] : false;
653 9
            if (is_callable($handler)) {
654 9
                $task = self::generatorTask();
655 9
                $task->hook($name, $handler, $override);
656 6
            } else {
657 3
                throw new PhpSmsException("Please give method static $name() a callable parameter");
658
            }
659 6
        } else {
660
            throw new PhpSmsException("Do not find static method $name()");
661
        }
662 9
    }
663
664
    /**
665
     * overload method
666
     *
667
     * @param $name
668
     * @param $args
669
     *
670
     * @throws PhpSmsException
671
     * @throws \Exception
672
     */
673 3
    public function __call($name, $args)
674
    {
675
        try {
676 3
            $this->__callStatic($name, $args);
677 2
        } catch (\Exception $e) {
678
            throw $e;
679
        }
680 3
    }
681
682
    /**
683
     * serialize magic method
684
     * store current sms instance status
685
     *
686
     * @return array
687
     */
688 3
    public function __sleep()
689
    {
690 3
        $this->_status_before_enqueue_['enableAgents'] = self::serializeEnableAgents();
691 3
        $this->_status_before_enqueue_['agentsConfig'] = self::getAgentsConfig();
692 3
        $this->_status_before_enqueue_['handlers'] = self::serializeHandlers();
693
694 3
        return ['pushedToQueue', 'smsData', 'firstAgent', '_status_before_enqueue_'];
695
    }
696
697
    /**
698
     * unserialize magic method
699
     * note: the force bootstrap must before reinstall handlers!
700
     */
701 3
    public function __wakeup()
702
    {
703 3
        $status = $this->_status_before_enqueue_;
704 3
        self::$agentsName = self::unserializeEnableAgents($status['enableAgents']);
705 3
        self::$agentsConfig = $status['agentsConfig'];
706 3
        self::bootstrap(true);
707 3
        self::reinstallHandlers($status['handlers']);
708 3
    }
709
710
    /**
711
     * get a serializer
712
     *
713
     * @return Serializer
714
     */
715 3
    public static function getSerializer()
716
    {
717 3
        if (!self::$serializer) {
718 3
            self::$serializer = new Serializer();
719 2
        }
720
721 3
        return self::$serializer;
722
    }
723
724
    /**
725
     * serialize enable agents
726
     *
727
     * @return array
728
     */
729 3
    protected static function serializeEnableAgents()
730
    {
731 3
        $enableAgents = self::getEnableAgents();
732 3
        foreach ($enableAgents as $name => &$options) {
733 3
            if (is_array($options)) {
734 3
                self::serializeClosureAndReplace($options, 'sendSms');
735 3
                self::serializeClosureAndReplace($options, 'voiceVerify');
736 2
            }
737 2
        }
738
739 3
        return $enableAgents;
740
    }
741
742
    /**
743
     * unserialize enable agents
744
     *
745
     * @param array $serialized
746
     *
747
     * @return mixed
748
     */
749 3
    protected static function unserializeEnableAgents(array $serialized)
750
    {
751 3
        foreach ($serialized as $name => &$options) {
752 3
            if (is_array($options)) {
753 3
                self::unserializeToClosureAndReplace($options, 'sendSms');
754 3
                self::unserializeToClosureAndReplace($options, 'voiceVerify');
755 2
            }
756 2
        }
757
758 3
        return $serialized;
759
    }
760
761
    /**
762
     * serialize character closure value of a array and replace origin value
763
     *
764
     * @param array $options
765
     * @param       $key
766
     */
767 3
    protected static function serializeClosureAndReplace(array &$options, $key)
768
    {
769 3
        if (isset($options["$key"]) && is_callable($options["$key"])) {
770 3
            $serializer = self::getSerializer();
771 3
            $options["$key"] = (string) $serializer->serialize($options["$key"]);
772 2
        }
773 3
    }
774
775
    /**
776
     * unserialize character string of a array to closure and replace origin value
777
     *
778
     * @param array $options
779
     * @param       $key
780
     */
781 3
    protected static function unserializeToClosureAndReplace(array &$options, $key)
782
    {
783 3
        if (isset($options["$key"])) {
784 3
            $serializer = self::getSerializer();
785 3
            $options["$key"] = $serializer->unserialize($options["$key"]);
786 2
        }
787 3
    }
788
789
    /**
790
     * serialize these hooks` handlers:
791
     * 'beforeRun','beforeDriverRun','afterDriverRun','afterRun'
792
     *
793
     * @return array
794
     */
795 3
    protected static function serializeHandlers()
796
    {
797 3
        $hooks = [];
798 3
        $serializer = self::getSerializer();
799 3
        $task = self::generatorTask();
800 3
        foreach ($task->handlers as $hookName => $handlers) {
801 3
            foreach ($handlers as $handler) {
802 3
                $serialized = $serializer->serialize($handler);
803 3
                if (!isset($hooks[$hookName])) {
804 3
                    $hooks[$hookName] = [];
805 2
                }
806 3
                array_push($hooks[$hookName], $serialized);
807 2
            }
808 2
        }
809
810 3
        return $hooks;
811
    }
812
813
    /**
814
     * reinstall hooks` handlers by serialized handlers
815
     *
816
     * @param array $handlers
817
     */
818 3
    protected static function reinstallHandlers(array $handlers)
819
    {
820 3
        $serializer = self::getSerializer();
821 3
        foreach ($handlers as $hookName => $serializedHandlers) {
822 3
            foreach ($serializedHandlers as $index => $handler) {
823 3
                if (is_string($handler)) {
824 3
                    $handler = $serializer->unserialize($handler);
825 2
                }
826 3
                $override = $index === 0;
827 3
                self::$hookName($handler, $override);
828 2
            }
829 2
        }
830 3
    }
831
}
832