Completed
Pull Request — master (#54)
by lan tian
02:25
created

Sms::getTask()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
crap 2
1
<?php
2
3
namespace Toplan\PhpSms;
4
5
use SuperClosure\Serializer;
6
use Toplan\TaskBalance\Balancer;
7
use Toplan\TaskBalance\Task;
8
9
/**
10
 * Class Sms
11
 *
12
 *
13
 * @author toplan<[email protected]>
14
 */
15
class Sms
16
{
17
    /**
18
     * Send task`s name.
19
     *
20
     * @var string
21
     */
22
    const TASK = 'PhpSms';
23
24
    /**
25
     * SMS agents(service providers),
26
     * they are instances of class [Toplan\PhpSms\Agent].
27
     *
28
     * @var array
29
     */
30
    protected static $agents = [];
31
32
    /**
33
     * The enabled agents` name.
34
     *
35
     * @var array
36
     */
37
    protected static $agentsName = [];
38
39
    /**
40
     * The enabled agents` config info.
41
     *
42
     * @var array
43
     */
44
    protected static $agentsConfig = [];
45
46
    /**
47
     * Whether to use queue.
48
     *
49
     * @var bool
50
     */
51
    protected static $enableQueue = false;
52
53
    /**
54
     * How to push to queue.
55
     *
56
     * @var \Closure
57
     */
58
    protected static $howToUseQueue = null;
59
60
    /**
61
     * The enable hooks for balance task.
62
     *
63
     * @var array
64
     */
65
    protected static $enableHooks = [
66
        'beforeRun',
67
        'beforeDriverRun',
68
        'afterDriverRun',
69
        'afterRun',
70
    ];
71
72
    /**
73
     * An instance of class [SuperClosure\Serializer]
74
     *
75
     * @var Serializer
76
     */
77
    protected static $serializer = null;
78
79
    /**
80
     * SMS(or voice verify) data container.
81
     *
82
     * @var array
83
     */
84
    protected $smsData = [
85
        'to'           => null,
86
        'templates'    => [],
87
        'content'      => null,
88
        'templateData' => [],
89
        'voiceCode'    => null,
90
    ];
91
92
    /**
93
     * The name of first agent.
94
     *
95
     * @var string|null
96
     */
97
    protected $firstAgent = null;
98
99
    /**
100
     * Whether the current instance has already pushed to queue.
101
     *
102
     * @var bool
103
     */
104
    protected $pushedToQueue = false;
105
106
    /**
107
     * Status container,
108
     * store config data before serialize a instance(before enqueue).
109
     *
110
     * @var array
111
     */
112
    protected $_status_before_enqueue_ = [];
113
114
    /**
115
     * Constructor
116
     *
117
     * @param bool $autoBoot
118
     */
119 6
    public function __construct($autoBoot = true)
120
    {
121 6
        if ($autoBoot) {
122 6
            self::bootstrap();
123 6
        }
124 6
    }
125
126
    /**
127
     * Boot balanced send task.
128
     */
129 9
    public static function bootstrap()
130
    {
131 9
        $task = self::getTask();
132 9
        if (!count($task->drivers)) {
133 6
            self::configuration();
134 6
            self::createDrivers($task);
135 6
        }
136 9
    }
137
138
    /**
139
     * Get or generate a balanced task instance for send SMS/voice verify.
140
     *
141
     * @return Task
142
     */
143 18
    public static function getTask()
144
    {
145 18
        if (!Balancer::hasTask(self::TASK)) {
146 6
            Balancer::task(self::TASK);
147 6
        }
148
149 18
        return Balancer::getTask(self::TASK);
150
    }
151
152
    /**
153
     * Configuration.
154
     */
155 6
    protected static function configuration()
156
    {
157 6
        $config = [];
158 6
        if (empty(self::$agentsName)) {
159 3
            self::initEnableAgents($config);
160 3
        }
161 6
        self::initAgentsConfig($config);
162 6
        self::validateConfig();
163 6
    }
164
165
    /**
166
     * Try to read and set enable agents` name from config file.
167
     *
168
     * @param array $config
169
     */
170 3
    protected static function initEnableAgents(array &$config)
171
    {
172 3
        $config = $config ?: include __DIR__ . '/../config/phpsms.php';
173 3
        $enableAgents = isset($config['enable']) ? $config['enable'] : null;
174 3
        self::enable($enableAgents);
175 3
    }
176
177
    /**
178
     * Try to read and set enabled agents` config from config file.
179
     *
180
     * @param array $config
181
     */
182 6
    protected static function initAgentsConfig(array &$config)
183
    {
184 6
        $diff = array_diff_key(self::$agentsName, self::$agentsConfig);
185 6
        $diff = array_keys($diff);
186 6
        if (count($diff)) {
187 3
            $config = $config ?: include __DIR__ . '/../config/phpsms.php';
188 3
            $agentsConfig = isset($config['agents']) ? $config['agents'] : [];
189 3
            foreach ($diff as $name) {
190 3
                $agentConfig = isset($agentsConfig[$name]) ? $agentsConfig[$name] : [];
191 3
                self::agents($name, $agentConfig);
192 3
            }
193 3
        }
194 6
    }
195
196
    /**
197
     * validate configuration.
198
     *
199
     * @throws PhpSmsException
200
     */
201 6
    protected static function validateConfig()
202
    {
203 6
        if (!count(self::$agentsName)) {
204
            throw new PhpSmsException('Please configure at least one agent');
205
        }
206 6
    }
207
208
    /**
209
     * Create drivers of the balanced task.
210
     *
211
     * @param Task $task
212
     */
213 18
    protected static function createDrivers(Task $task)
214
    {
215 6
        foreach (self::$agentsName as $name => $options) {
216
            //获取代理器配置
217 6
            $configData = self::getAgentConfigData($name);
218
            //解析代理器数组模式的调度配置
219 6
            if (is_array($options)) {
220 3
                $data = self::parseAgentArrayOptions($options);
221 3
                $configData = array_merge($configData, $data);
222 3
                $options = $data['driverOpts'];
223 3
            }
224
            //创建任务驱动器
225 6
            $task->driver("$name $options")->data($configData)
226 18
                 ->work(function ($driver) {
227 18
                     $configData = $driver->getDriverData();
228 18
                     $agent = self::getSmsAgent($driver->name, $configData);
229 18
                     $smsData = $driver->getTaskData();
230 18
                     extract($smsData);
231 18
                     if (isset($smsData['voiceCode']) && $smsData['voiceCode']) {
232
                         $agent->voiceVerify($to, $voiceCode);
233
                     } else {
234 18
                         $template = isset($templates[$driver->name]) ? $templates[$driver->name] : 0;
235 18
                         $agent->sendSms($template, $to, $templateData, $content);
236
                     }
237 18
                     $result = $agent->result();
238 18
                     if ($result['success']) {
239 18
                         $driver->success();
240 18
                     }
241 18
                     unset($result['success']);
242
243 18
                     return $result;
244 6
                 });
245 6
        }
246 6
    }
247
248
    /**
249
     * Parse the enabled agents` scheduling config data.
250
     * 解析可用代理器的数组模式的调度配置
251
     *
252
     * @param array $options
253
     *
254
     * @return array
255
     */
256 3
    protected static function parseAgentArrayOptions(array $options)
257
    {
258 3
        $agentClass = self::pullAgentOptionByName($options, 'agentClass');
259 3
        $sendSms = self::pullAgentOptionByName($options, 'sendSms');
260 3
        $voiceVerify = self::pullAgentOptionByName($options, 'voiceVerify');
261 3
        $backup = self::pullAgentOptionByName($options, 'backup') ? 'backup' : '';
262 3
        $driverOpts = implode(' ', array_values($options)) . " $backup";
263
264 3
        return compact('agentClass', 'sendSms', 'voiceVerify', 'driverOpts');
265
    }
266
267
    /**
268
     * Pull the character option data from the scheduling config.
269
     *
270
     * @param array  $options
271
     * @param string $name
272
     *
273
     * @return mixed
274
     */
275 3
    protected static function pullAgentOptionByName(array &$options, $name)
276
    {
277 3
        if (!isset($options[$name])) {
278 3
            return;
279
        }
280 3
        $value = $options[$name];
281 3
        unset($options[$name]);
282
283 3
        return $value;
284
    }
285
286
    /**
287
     * Get agent config data by name.
288
     *
289
     * @param string $name
290
     *
291
     * @return array
292
     */
293 6
    protected static function getAgentConfigData($name)
294
    {
295 6
        return isset(self::$agentsConfig[$name]) ? self::$agentsConfig[$name] : [];
296
    }
297
298
    /**
299
     * Get a sms agent instance by agent name,
300
     * if null, will try to create a new agent instance.
301
     *
302
     * @param string $name
303
     * @param array  $configData
304
     *
305
     * @throws PhpSmsException
306
     *
307
     * @return mixed
308
     */
309 21
    public static function getSmsAgent($name, array $configData)
310
    {
311 21
        if (!isset(self::$agents[$name])) {
312 6
            $configData['name'] = $name;
313 6
            $className = isset($configData['agentClass']) ? $configData['agentClass'] : ('Toplan\\PhpSms\\' . $name . 'Agent');
314 6
            if ((isset($configData['sendSms']) && is_callable($configData['sendSms'])) ||
315 6
                (isset($configData['voiceVerify']) && is_callable($configData['voiceVerify']))) {
316
                //创建寄生代理器
317 3
                $configData['agentClass'] = '';
318 3
                self::$agents[$name] = new ParasiticAgent($configData);
319 6
            } elseif (class_exists($className)) {
320
                //创建新代理器
321 3
                self::$agents[$name] = new $className($configData);
322 3
            } else {
323
                //无代理器可用
324
                throw new PhpSmsException("Do not support [$name] agent.");
325
            }
326 6
        }
327
328 21
        return self::$agents[$name];
329
    }
330
331
    /**
332
     * Set enable agents.
333
     *
334
     * @param mixed $agentName
335
     * @param mixed $options
336
     */
337 6
    public static function enable($agentName, $options = null)
338
    {
339 6
        if (is_array($agentName)) {
340 6
            foreach ($agentName as $name => $opt) {
341 6
                self::enable($name, $opt);
342 6
            }
343 6
        } elseif ($agentName && is_string($agentName) && $options !== null) {
344 3
            self::$agentsName["$agentName"] = is_array($options) ? $options : "$options";
345 6
        } elseif (is_int($agentName) && !is_array($options) && "$options") {
346 3
            self::$agentsName["$options"] = '1';
347 6
        } elseif ($agentName && $options === null) {
348 3
            self::$agentsName["$agentName"] = '1';
349 3
        }
350 6
    }
351
352
    /**
353
     * Set config info by agent name.
354
     *
355
     * @param array|string $agentName
356
     * @param array        $config
357
     *
358
     * @throws PhpSmsException
359
     */
360 6
    public static function agents($agentName, array $config = [])
361
    {
362 6
        if (is_array($agentName)) {
363 3
            foreach ($agentName as $name => $conf) {
364 3
                self::agents($name, $conf);
365 3
            }
366 6
        } elseif ($agentName && is_array($config)) {
367 6
            if (preg_match('/^[0-9]+$/', $agentName)) {
368
                throw new PhpSmsException("Agent name [$agentName] must be string, could not be a pure digital");
369 3
            }
370 6
            self::$agentsConfig["$agentName"] = $config;
371 6
        }
372 6
    }
373
374
    /**
375
     * Get the enabled agents` name.
376
     *
377
     * @return array
378
     */
379 12
    public static function getEnableAgents()
380
    {
381 12
        return self::$agentsName;
382
    }
383
384
    /**
385
     * Get the enabled agents` config info.
386
     *
387
     * @return array
388
     */
389 12
    public static function getAgentsConfig()
390
    {
391 12
        return self::$agentsConfig;
392
    }
393
394
    /**
395
     * Tear down enable agents and prepare to create and start a new balance task,
396
     * so before do it must destroy old task instance.
397
     */
398 6
    public static function cleanEnableAgents()
399
    {
400 6
        Balancer::destroy(self::TASK);
401 6
        self::$agentsName = [];
402 6
    }
403
404
    /**
405
     * Tear down agents config and prepare to create and start a new balance task,
406
     * so before do it must destroy old task instance.
407
     */
408 3
    public static function cleanAgentsConfig()
409
    {
410 3
        Balancer::destroy(self::TASK);
411 3
        self::$agentsConfig = [];
412 3
    }
413
414
    /**
415
     * Create a sms instance which send SMS,
416
     * and set SMS templates or content.
417
     *
418
     * @param mixed $agentName
419
     * @param mixed $tempId
420
     *
421
     * @return Sms
422
     */
423
    public static function make($agentName = null, $tempId = null)
424
    {
425
        $sms = new self();
426
        if (is_array($agentName)) {
427
            $sms->template($agentName);
428
        } elseif ($agentName && is_string($agentName)) {
429
            if ($tempId === null) {
430
                $sms->content($agentName);
431
            } elseif (is_string("$tempId")) {
432
                $sms->template($agentName, $tempId);
433
            }
434
        }
435
436
        return $sms;
437
    }
438
439
    /**
440
     * Create a sms instance which send voice verify,
441
     * and set verify code.
442
     *
443
     * @param string|int $code
444
     *
445
     * @return Sms
446
     */
447 3
    public static function voice($code)
448
    {
449 3
        $sms = new self();
450 3
        $sms->smsData['voiceCode'] = $code;
451
452 3
        return $sms;
453
    }
454
455
    /**
456
     * Set whether to use queue, and define how to use queue.
457
     *
458
     * @param mixed $enable
459
     * @param mixed $handler
460
     *
461
     * @return bool
462
     */
463 3
    public static function queue($enable = null, $handler = null)
464
    {
465 3
        if ($enable === null && $handler === null) {
466 3
            return self::$enableQueue;
467
        }
468 3
        if (is_callable($enable)) {
469 3
            $handler = $enable;
470 3
            $enable = true;
471 3
        }
472 3
        self::$enableQueue = (bool) $enable;
473 3
        if (is_callable($handler)) {
474 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...
475 3
        }
476
477 3
        return self::$enableQueue;
478
    }
479
480
    /**
481
     * Set the receiver`s mobile number.
482
     *
483
     * @param string $mobile
484
     *
485
     * @return $this
486
     */
487 6
    public function to($mobile)
488
    {
489 6
        $this->smsData['to'] = $mobile;
490
491 6
        return $this;
492
    }
493
494
    /**
495
     * Set content for content SMS.
496
     *
497
     * @param string $content
498
     *
499
     * @return $this
500
     */
501 3
    public function content($content)
502
    {
503 3
        $this->smsData['content'] = trim((string) $content);
504
505 3
        return $this;
506
    }
507
508
    /**
509
     * Set template id for template SMS.
510
     *
511
     * @param mixed $agentName
512
     * @param mixed $tempId
513
     *
514
     * @return $this
515
     */
516 3
    public function template($agentName, $tempId = null)
517
    {
518 3
        if (is_array($agentName)) {
519 3
            foreach ($agentName as $k => $v) {
520 3
                $this->template($k, $v);
521 3
            }
522 3
        } elseif ($agentName && $tempId) {
523 3
            if (!isset($this->smsData['templates']) || !is_array($this->smsData['templates'])) {
524
                $this->smsData['templates'] = [];
525
            }
526 3
            $this->smsData['templates']["$agentName"] = $tempId;
527 3
        }
528
529 3
        return $this;
530
    }
531
532
    /**
533
     * Set template data for template SMS.
534
     *
535
     * @param array $data
536
     *
537
     * @return $this
538
     */
539 3
    public function data(array $data)
540
    {
541 3
        $this->smsData['templateData'] = $data;
542
543 3
        return $this;
544
    }
545
546
    /**
547
     * Set the first agent by agent`s name.
548
     *
549
     * @param string $name
550
     *
551
     * @return $this
552
     */
553 3
    public function agent($name)
554
    {
555 3
        $this->firstAgent = (string) $name;
556
557 3
        return $this;
558
    }
559
560
    /**
561
     * Start send SMS/voice verify.
562
     *
563
     * If give a true parameter, will immediately start whatever whether to use queue.
564
     * if you are already pushed sms instance to queue, you can recall the method `send()` in queue job without `true` parameter,
565
     * so this mechanism in order to make you convenient use the method `send()` in queue system.
566
     *
567
     * @param bool $immediately
568
     *
569
     * @return mixed
570
     */
571 18
    public function send($immediately = false)
572
    {
573 18
        if (!self::$enableQueue || $this->pushedToQueue) {
574 18
            $immediately = true;
575 18
        }
576 18
        if ($immediately) {
577 18
            $result = Balancer::run(self::TASK, [
578 18
                'data'   => $this->getData(),
579 18
                'driver' => $this->firstAgent,
580 18
            ]);
581 18
        } else {
582 3
            $result = $this->push();
583
        }
584
585 18
        return $result;
586
    }
587
588
    /**
589
     * Push to queue by custom method.
590
     *
591
     * @throws \Exception | PhpSmsException
592
     *
593
     * @return mixed
594
     */
595 3
    public function push()
596
    {
597 3
        if (is_callable(self::$howToUseQueue)) {
598
            try {
599 3
                $this->pushedToQueue = true;
600
601 3
                return call_user_func_array(self::$howToUseQueue, [$this, $this->smsData]);
602
            } catch (\Exception $e) {
603
                $this->pushedToQueue = false;
604
                throw $e;
605
            }
606
        } else {
607
            throw new PhpSmsException('Please define how to use queue by method `queue($enable, $handler)`');
608
        }
609
    }
610
611
    /**
612
     * Get all the data of SMS/voice verify.
613
     *
614
     * @param null|string $name
615
     *
616
     * @return mixed
617
     */
618 36
    public function getData($name = null)
619
    {
620 36
        if (is_string($name) && isset($this->smsData["$name"])) {
621 3
            return $this->smsData[$name];
622
        }
623
624 36
        return $this->smsData;
625
    }
626
627
    /**
628
     * Overload static method.
629
     *
630
     * @param string $name
631
     * @param array  $args
632
     *
633
     * @throws PhpSmsException
634
     */
635 9
    public static function __callStatic($name, $args)
636
    {
637 9
        $name = $name === 'beforeSend' ? 'beforeRun' : $name;
638 9
        $name = $name === 'afterSend' ? 'afterRun' : $name;
639 9
        $name = $name === 'beforeAgentSend' ? 'beforeDriverRun' : $name;
640 9
        $name = $name === 'afterAgentSend' ? 'afterDriverRun' : $name;
641 9
        if (in_array($name, self::$enableHooks)) {
642 9
            $handler = $args[0];
643 9
            $override = isset($args[1]) ? (bool) $args[1] : false;
644 9
            if (is_callable($handler)) {
645 9
                $task = self::getTask();
646 9
                $task->hook($name, $handler, $override);
647 9
            } else {
648
                throw new PhpSmsException("Please give method static $name() a callable parameter");
649
            }
650 9
        } else {
651
            throw new PhpSmsException("Do not find static method $name()");
652
        }
653 9
    }
654
655
    /**
656
     * Overload method.
657
     *
658
     * @param string $name
659
     * @param array  $args
660
     *
661
     * @throws PhpSmsException
662
     * @throws \Exception
663
     */
664 3
    public function __call($name, $args)
665
    {
666
        try {
667 3
            $this->__callStatic($name, $args);
668 3
        } catch (\Exception $e) {
669
            throw $e;
670
        }
671 3
    }
672
673
    /**
674
     * Serialize magic method,
675
     * store current sms instance status.
676
     *
677
     * @return array
678
     */
679 3
    public function __sleep()
680
    {
681
        try {
682 3
            $this->_status_before_enqueue_['enableAgents'] = self::serializeEnableAgents();
683 3
            $this->_status_before_enqueue_['agentsConfig'] = self::getAgentsConfig();
684 3
            $this->_status_before_enqueue_['handlers'] = self::serializeHandlers();
685 3
        } catch (\Exception $e) {
686
            //swallow exception
687
        }
688
689 3
        return ['pushedToQueue', 'smsData', 'firstAgent', '_status_before_enqueue_'];
690
    }
691
692
    /**
693
     * Unserialize magic method,
694
     * note: the force bootstrap must before reinstall handlers!
695
     */
696 3
    public function __wakeup()
697
    {
698 3
        if (empty($this->_status_before_enqueue_)) {
699
            return;
700
        }
701 3
        $status = $this->_status_before_enqueue_;
702 3
        self::$agentsName = self::unserializeEnableAgents($status['enableAgents']);
703 3
        self::$agentsConfig = $status['agentsConfig'];
704 3
        Balancer::destroy(self::TASK);
705 3
        self::bootstrap();
706 3
        self::reinstallHandlers($status['handlers']);
707 3
    }
708
709
    /**
710
     * Get a closure serializer.
711
     *
712
     * @return Serializer
713
     */
714 3
    public static function getSerializer()
715
    {
716 3
        if (!self::$serializer) {
717 3
            self::$serializer = new Serializer();
718 3
        }
719
720 3
        return self::$serializer;
721
    }
722
723
    /**
724
     * Serialize enabled agents.
725
     *
726
     * @return array
727
     */
728 3
    protected static function serializeEnableAgents()
729
    {
730 3
        $enableAgents = self::getEnableAgents();
731 3
        foreach ($enableAgents as $name => &$options) {
732 3
            if (is_array($options)) {
733 3
                self::serializeClosureAndReplace($options, 'sendSms');
734 3
                self::serializeClosureAndReplace($options, 'voiceVerify');
735 3
            }
736 3
        }
737
738 3
        return $enableAgents;
739
    }
740
741
    /**
742
     * Unserialize enabled agents.
743
     *
744
     * @param array $serialized
745
     *
746
     * @return mixed
747
     */
748 3
    protected static function unserializeEnableAgents(array $serialized)
749
    {
750 3
        foreach ($serialized as $name => &$options) {
751 3
            if (is_array($options)) {
752 3
                self::unserializeToClosureAndReplace($options, 'sendSms');
753 3
                self::unserializeToClosureAndReplace($options, 'voiceVerify');
754 3
            }
755 3
        }
756
757 3
        return $serialized;
758
    }
759
760
    /**
761
     * Serialize character closure value of a array and replace origin value.
762
     *
763
     * @param array  $options
764
     * @param string $key
765
     */
766 3
    protected static function serializeClosureAndReplace(array &$options, $key)
767
    {
768 3
        if (isset($options["$key"]) && is_callable($options["$key"])) {
769 3
            $serializer = self::getSerializer();
770 3
            $options["$key"] = (string) $serializer->serialize($options["$key"]);
771 3
        }
772 3
    }
773
774
    /**
775
     * Unserialize character string of a array to closure and replace origin value.
776
     *
777
     * @param array  $options
778
     * @param string $key
779
     */
780 3
    protected static function unserializeToClosureAndReplace(array &$options, $key)
781
    {
782 3
        if (isset($options["$key"])) {
783 3
            $serializer = self::getSerializer();
784 3
            $options["$key"] = $serializer->unserialize($options["$key"]);
785 3
        }
786 3
    }
787
788
    /**
789
     * Serialize these hooks` handlers:
790
     * 'beforeRun','beforeDriverRun','afterDriverRun','afterRun'.
791
     *
792
     * @return array
793
     */
794 3
    protected static function serializeHandlers()
795
    {
796 3
        $hooks = [];
797 3
        $serializer = self::getSerializer();
798 3
        $task = self::getTask();
799 3
        foreach ($task->handlers as $hookName => $handlers) {
800 3
            foreach ($handlers as $handler) {
801 3
                $serialized = $serializer->serialize($handler);
802 3
                if (!isset($hooks[$hookName])) {
803 3
                    $hooks[$hookName] = [];
804 3
                }
805 3
                array_push($hooks[$hookName], $serialized);
806 3
            }
807 3
        }
808
809 3
        return $hooks;
810
    }
811
812
    /**
813
     * Reinstall balance task hooks` handlers by serialized handlers.
814
     *
815
     * @param array $handlers
816
     */
817 3
    protected static function reinstallHandlers(array $handlers)
818
    {
819 3
        $serializer = self::getSerializer();
820 3
        foreach ($handlers as $hookName => $serializedHandlers) {
821 3
            foreach ($serializedHandlers as $index => $handler) {
822 3
                if (is_string($handler)) {
823 3
                    $handler = $serializer->unserialize($handler);
824 3
                }
825 3
                self::$hookName($handler, $index === 0);
826 3
            }
827 3
        }
828 3
    }
829
}
830