Completed
Push — master ( 67b201...64a3e6 )
by Lars
02:31 queued 11s
created

src/voku/cache/Cache.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
declare(strict_types=1);
4
5
namespace voku\cache;
6
7
use voku\cache\Exception\InvalidArgumentException;
8
9
/**
10
 * Cache: global-cache class
11
 *
12
 * can use different cache-adapter:
13
 * - Redis
14
 * - Memcache / Memcached
15
 * - APC / APCu
16
 * - Xcache
17
 * - Array
18
 * - File / OpCache
19
 */
20
class Cache implements iCache
21
{
22
    /**
23
     * @var iAdapter
24
     */
25
    protected $adapter;
26
27
    /**
28
     * @var iSerializer
29
     */
30
    protected $serializer;
31
32
    /**
33
     * @var string
34
     */
35
    protected $prefix = '';
36
37
    /**
38
     * @var bool
39
     */
40
    protected $isReady = false;
41
42
    /**
43
     * @var bool
44
     */
45
    protected $isActive = true;
46
47
    /**
48
     * @var bool
49
     */
50
    protected $useCheckForDev;
51
52
    /**
53
     * @var bool
54
     */
55
    protected $useCheckForAdminSession;
56
57
    /**
58
     * @var bool
59
     */
60
    protected $useCheckForServerIpIsClientIp;
61
62
    /**
63
     * @var string
64
     */
65
    protected $disableCacheGetParameter;
66
67
    /**
68
     * @var bool
69
     */
70
    protected $isAdminSession;
71
72
    /**
73
     * @var array
74
     */
75
    protected static $STATIC_CACHE = [];
76
77
    /**
78
     * @var array
79
     */
80
    protected static $STATIC_CACHE_EXPIRE = [];
81
82
    /**
83
     * @var array
84
     */
85
    protected static $STATIC_CACHE_COUNTER = [];
86
87
    /**
88
     * @var int
89
     */
90
    protected $staticCacheHitCounter = 10;
91
92
    /**
93
     * __construct
94
     *
95
     * @param iAdapter|null    $adapter
96
     * @param iSerializer|null $serializer
97
     * @param bool             $checkForUsage                 <p>admin-session || server-ip == client-ip || check for
98
     *                                                        dev</p>
99
     * @param bool             $cacheEnabled                  <p>false will disable the cache (use it e.g. for global
100
     *                                                        settings)</p>
101
     * @param bool|string      $isAdminSession                <p>set a admin-id, if the user is a admin (so we can
102
     *                                                        disable cache for this user)
103
     * @param bool             $useCheckForAdminSession       <p>use $isAdminSession flag or not</p>
104
     * @param bool             $useCheckForDev                <p>use checkForDev() or not</p>
105
     * @param bool             $useCheckForServerIpIsClientIp <p>use check for server-ip == client-ip or not</p>
106
     * @param string           $disableCacheGetParameter      <p>set the _GET parameter for disabling the cache,
107
     *                                                        disable this check via empty string</p>
108
     */
109 65
    public function __construct(
110
        iAdapter $adapter = null,
111
        iSerializer $serializer = null,
112
        bool $checkForUsage = true,
113
        bool $cacheEnabled = true,
114
        bool $isAdminSession = false,
115
        bool $useCheckForDev = true,
116
        bool $useCheckForAdminSession = true,
117
        bool $useCheckForServerIpIsClientIp = true,
118
        string $disableCacheGetParameter = 'testWithoutCache'
119
    ) {
120 65
        $this->isAdminSession = $isAdminSession;
0 ignored issues
show
Documentation Bug introduced by
It seems like $isAdminSession can also be of type string. However, the property $isAdminSession is declared as type boolean. 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...
121
122 65
        $this->useCheckForDev = $useCheckForDev;
123 65
        $this->useCheckForAdminSession = $useCheckForAdminSession;
124 65
        $this->useCheckForServerIpIsClientIp = $useCheckForServerIpIsClientIp;
125
126 65
        $this->disableCacheGetParameter = $disableCacheGetParameter;
127
128
        // First check if the cache is active at all.
129 65
        $this->isActive = $cacheEnabled;
130
        if (
131 65
            $this->isActive === true
132
            &&
133 65
            $checkForUsage === true
134
        ) {
135
            $this->setActive($this->isCacheActiveForTheCurrentUser());
136
        }
137
138
        // If the cache is active, then try to auto-connect to the best possible cache-system.
139 65
        if ($this->isActive === true) {
140 65
            $this->setPrefix($this->getTheDefaultPrefix());
141
142 65
            if ($adapter === null) {
143
                $adapter = $this->autoConnectToAvailableCacheSystem();
144
            }
145
146
            // INFO: Memcache(d) has his own "serializer", so don't use it twice
147 65
            if (!\is_object($serializer) && $serializer === null) {
148
                if (
149
                    $adapter instanceof AdapterMemcached
150
                    ||
151
                    $adapter instanceof AdapterMemcache
152
                ) {
153
                    $serializer = new SerializerNo();
154
                } else {
155
                    // set default serializer
156
                    $serializer = new SerializerIgbinary();
157
                }
158
            }
159
        }
160
161
        // Final checks ...
162
        if (
163 65
            $serializer !== null
164
            &&
165 65
            $adapter !== null
166
        ) {
167 65
            $this->setCacheIsReady(true);
168
169 65
            $this->adapter = $adapter;
170 65
            $this->serializer = $serializer;
171
        }
172 65
    }
173
174
    /**
175
     * enable / disable the cache
176
     *
177
     * @param bool $isActive
178
     */
179
    public function setActive(bool $isActive)
180
    {
181
        $this->isActive = $isActive;
182
    }
183
184
    /**
185
     * check if the current use is a admin || dev || server == client
186
     *
187
     * @return bool
188
     */
189
    public function isCacheActiveForTheCurrentUser(): bool
190
    {
191
        $active = true;
192
193
        // test the cache, with this GET-parameter
194
        if ($this->disableCacheGetParameter) {
195
            $testCache = isset($_GET[$this->disableCacheGetParameter]) ? (int) $_GET[$this->disableCacheGetParameter] : 0;
196
        } else {
197
            $testCache = 0;
198
        }
199
200
        if ($testCache !== 1) {
201
            if (
202
                // admin session is active
203
                (
204
                    $this->useCheckForAdminSession
205
                    &&
206
                    $this->isAdminSession
207
                )
208
                ||
209
                // server == client
210
                (
211
                    $this->useCheckForServerIpIsClientIp === true
212
                    &&
213
                    isset($_SERVER['SERVER_ADDR'])
214
                    &&
215
                    $_SERVER['SERVER_ADDR'] === $this->getClientIp()
216
                )
217
                ||
218
                // user is a dev
219
                (
220
                    $this->useCheckForDev === true
221
                    &&
222
                    $this->checkForDev() === true
223
                )
224
            ) {
225
                $active = false;
226
            }
227
        }
228
229
        return $active;
230
    }
231
232
    /**
233
     * returns the IP address of the client
234
     *
235
     * @param bool $trust_proxy_headers     <p>
236
     *                                      Whether or not to trust the
237
     *                                      proxy headers HTTP_CLIENT_IP
238
     *                                      and HTTP_X_FORWARDED_FOR. ONLY
239
     *                                      use if your $_SERVER is behind a
240
     *                                      proxy that sets these values
241
     *                                      </p>
242
     *
243
     * @return string
244
     */
245
    protected function getClientIp(bool $trust_proxy_headers = false): string
246
    {
247
        $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? 'NO_REMOTE_ADDR';
248
249
        if ($trust_proxy_headers) {
250
            return $remoteAddr;
251
        }
252
253
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
254
            $ip = $_SERVER['HTTP_CLIENT_IP'];
255
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
256
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
257
        } else {
258
            $ip = $remoteAddr;
259
        }
260
261
        return $ip;
262
    }
263
264
    /**
265
     * Check for local developer.
266
     *
267
     * @return bool
268
     */
269
    protected function checkForDev(): bool
270
    {
271
        $return = false;
272
273
        if (\function_exists('checkForDev')) {
274
            $return = checkForDev();
275
        } else {
276
277
            // for testing with dev-address
278
            $noDev = isset($_GET['noDev']) ? (int) $_GET['noDev'] : 0;
279
            $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? 'NO_REMOTE_ADDR';
280
281
            if (
282
                $noDev !== 1
283
                &&
284
                (
285
                    $remoteAddr === '127.0.0.1'
286
                    ||
287
                    $remoteAddr === '::1'
288
                    ||
289
                    \PHP_SAPI === 'cli'
290
                )
291
            ) {
292
                $return = true;
293
            }
294
        }
295
296
        return $return;
297
    }
298
299
    /**
300
     * Set the default-prefix via "SERVER"-var + "SESSION"-language.
301
     */
302 65
    protected function getTheDefaultPrefix(): string
303
    {
304 65
        return ($_SERVER['SERVER_NAME'] ?? '') . '_' .
305 65
               ($_SERVER['THEME'] ?? '') . '_' .
306 65
               ($_SERVER['STAGE'] ?? '') . '_' .
307 65
               ($_SESSION['language'] ?? '') . '_' .
308 65
               ($_SESSION['language_extra'] ?? '');
309
    }
310
311
    /**
312
     * Auto-connect to the available cache-system on the server.
313
     *
314
     * @return iAdapter
315
     */
316
    protected function autoConnectToAvailableCacheSystem(): iAdapter
317
    {
318
        static $adapterCache;
319
320
        if (\is_object($adapterCache) && $adapterCache instanceof iAdapter) {
321
            return $adapterCache;
322
        }
323
324
        $memcached = null;
325
        $isMemcachedAvailable = false;
326
        if (\extension_loaded('memcached')) {
327
            /** @noinspection PhpComposerExtensionStubsInspection */
328
            $memcached = new \Memcached();
329
            /** @noinspection PhpUsageOfSilenceOperatorInspection */
330
            $isMemcachedAvailable = @$memcached->addServer('127.0.0.1', 11211);
331
        }
332
333
        if ($isMemcachedAvailable === false) {
334
            $memcached = null;
335
        }
336
337
        $adapterMemcached = new AdapterMemcached($memcached);
338
        if ($adapterMemcached->installed() === true) {
339
340
            // -------------------------------------------------------------
341
            // "Memcached"
342
            // -------------------------------------------------------------
343
            $adapter = $adapterMemcached;
344
        } else {
345
            $memcache = null;
346
            $isMemcacheAvailable = false;
347
            /** @noinspection ClassConstantCanBeUsedInspection */
348
            if (\class_exists('\Memcache')) {
349
                /** @noinspection PhpComposerExtensionStubsInspection */
350
                $memcache = new \Memcache();
351
                /** @noinspection PhpUsageOfSilenceOperatorInspection */
352
                $isMemcacheAvailable = @$memcache->connect('127.0.0.1', 11211);
353
            }
354
355
            if ($isMemcacheAvailable === false) {
356
                $memcache = null;
357
            }
358
359
            $adapterMemcache = new AdapterMemcache($memcache);
360
            if ($adapterMemcache->installed() === true) {
361
362
                // -------------------------------------------------------------
363
                // "Memcache"
364
                // -------------------------------------------------------------
365
                $adapter = $adapterMemcache;
366
            } else {
367
                $redis = null;
368
                $isRedisAvailable = false;
369
                if (
370
                    \extension_loaded('redis')
371
                    &&
372
                    \class_exists('\Predis\Client')
373
                ) {
374
                    /** @noinspection PhpUndefinedNamespaceInspection */
375
                    /** @noinspection PhpUndefinedClassInspection */
376
                    $redis = new \Predis\Client(
377
                        [
378
                            'scheme'  => 'tcp',
379
                            'host'    => '127.0.0.1',
380
                            'port'    => 6379,
381
                            'timeout' => '2.0',
382
                        ]
383
                    );
384
385
                    try {
386
                        /** @noinspection PhpUndefinedMethodInspection */
387
                        $redis->connect();
388
                        /** @noinspection PhpUndefinedMethodInspection */
389
                        $isRedisAvailable = $redis->getConnection()->isConnected();
390
                    } catch (\Exception $e) {
391
                        // nothing
392
                    }
393
                }
394
395
                if ($isRedisAvailable === false) {
396
                    $redis = null;
397
                }
398
399
                $adapterRedis = new AdapterPredis($redis);
400
                if ($adapterRedis->installed() === true) {
401
402
                    // -------------------------------------------------------------
403
                    // Redis
404
                    // -------------------------------------------------------------
405
                    $adapter = $adapterRedis;
406
                } else {
407
                    $adapterXcache = new AdapterXcache();
408
                    if ($adapterXcache->installed() === true) {
409
410
                        // -------------------------------------------------------------
411
                        // "Xcache"
412
                        // -------------------------------------------------------------
413
                        $adapter = $adapterXcache;
414
                    } else {
415
                        $adapterApcu = new AdapterApcu();
416
                        if ($adapterApcu->installed() === true) {
417
418
                            // -------------------------------------------------------------
419
                            // "APCu"
420
                            // -------------------------------------------------------------
421
                            $adapter = $adapterApcu;
422
                        } else {
423
                            $adapterApc = new AdapterApc();
424
                            if ($adapterApc->installed() === true) {
425
426
                                // -------------------------------------------------------------
427
                                // "APC"
428
                                // -------------------------------------------------------------
429
                                $adapter = $adapterApc;
430
                            } else {
431
                                $adapterObCache = new AdapterOpCache();
432
                                if ($adapterObCache->installed() === true) {
433
434
                                    // -------------------------------------------------------------
435
                                    // OpCache (via PHP-files)
436
                                    // -------------------------------------------------------------
437
                                    $adapter = $adapterObCache;
438
                                } else {
439
440
                                    // -------------------------------------------------------------
441
                                    // Static-PHP-Cache
442
                                    // -------------------------------------------------------------
443
                                    $adapter = new AdapterArray();
444
                                }
445
                            }
446
                        }
447
                    }
448
                }
449
            }
450
        }
451
452
        // save to static cache
453
        $adapterCache = $adapter;
454
455
        return $adapter;
456
    }
457
458
    /**
459
     * Set "isReady" state.
460
     *
461
     * @param bool $isReady
462
     */
463 65
    protected function setCacheIsReady(bool $isReady)
464
    {
465 65
        $this->isReady = $isReady;
466 65
    }
467
468
    /**
469
     * Get the "isReady" state.
470
     *
471
     * @return bool
472
     */
473 5
    public function getCacheIsReady(): bool
474
    {
475 5
        return $this->isReady;
476
    }
477
478
    /**
479
     * Get cached-item by key.
480
     *
481
     * @param string $key
482
     * @param int    $forceStaticCacheHitCounter
483
     *
484
     * @return mixed
485
     */
486 31
    public function getItem(string $key, int $forceStaticCacheHitCounter = 0)
487
    {
488 31
        if (!$this->adapter instanceof iAdapter) {
489
            return null;
490
        }
491
492 31
        $storeKey = $this->calculateStoreKey($key);
493
494
        // check if we already using static-cache
495 31
        $useStaticCache = true;
496 31
        if ($this->adapter instanceof AdapterArray) {
497 6
            $useStaticCache = false;
498
        }
499
500 31
        if (!isset(self::$STATIC_CACHE_COUNTER[$storeKey])) {
501 24
            self::$STATIC_CACHE_COUNTER[$storeKey] = 0;
502
        }
503
504
        // get from static-cache
505
        if (
506 31
            $useStaticCache === true
507
            &&
508 31
            $this->checkForStaticCache($storeKey) === true
509
        ) {
510 8
            return self::$STATIC_CACHE[$storeKey];
511
        }
512
513 29
        $serialized = $this->adapter->get($storeKey);
514 29
        $value = $serialized ? $this->serializer->unserialize($serialized) : null;
515
516 29
        self::$STATIC_CACHE_COUNTER[$storeKey]++;
517
518
        // save into static-cache if needed
519
        if (
520 29
            $useStaticCache === true
521
            &&
522
            (
523
                (
524 23
                    $forceStaticCacheHitCounter !== 0
525
                    &&
526
                    self::$STATIC_CACHE_COUNTER[$storeKey] >= $forceStaticCacheHitCounter
527
                )
528
                ||
529
                (
530 23
                    $this->staticCacheHitCounter !== 0
531
                    &&
532 29
                    self::$STATIC_CACHE_COUNTER[$storeKey] >= $this->staticCacheHitCounter
533
                )
534
            )
535
        ) {
536 9
            self::$STATIC_CACHE[$storeKey] = $value;
537
        }
538
539 29
        return $value;
540
    }
541
542
    /**
543
     * Calculate store-key (prefix + $rawKey).
544
     *
545
     * @param string $rawKey
546
     *
547
     * @return string
548
     */
549 53
    protected function calculateStoreKey(string $rawKey): string
550
    {
551 53
        $str = $this->getPrefix() . $rawKey;
552
553 53
        if ($this->adapter instanceof AdapterFileAbstract) {
554 24
            $str = $this->cleanStoreKey($str);
555
        }
556
557 53
        return $str;
558
    }
559
560
    /**
561
     * Clean store-key (required e.g. for the "File"-Adapter).
562
     *
563
     * @param string $str
564
     *
565
     * @return string
566
     */
567 24
    protected function cleanStoreKey(string $str): string
568
    {
569 24
        return \md5($str);
570
    }
571
572
    /**
573
     * Get the prefix.
574
     *
575
     * @return string
576
     */
577 53
    public function getPrefix(): string
578
    {
579 53
        return $this->prefix;
580
    }
581
582
    /**
583
     * !!! Set the prefix. !!!
584
     *
585
     * WARNING: Do not use if you don't know what you do. Because this will overwrite the default prefix.
586
     *
587
     * @param string $prefix
588
     */
589 65
    public function setPrefix(string $prefix)
590
    {
591 65
        $this->prefix = $prefix;
592 65
    }
593
594
    /**
595
     * Get the current value, when the static cache is used.
596
     *
597
     * @return int
598
     */
599
    public function getStaticCacheHitCounter(): int
600
    {
601
        return $this->staticCacheHitCounter;
602
    }
603
604
    /**
605
     * Set the static-hit-counter: Who often do we hit the cache, before we use static cache?
606
     *
607
     * @param int $staticCacheHitCounter
608
     */
609
    public function setStaticCacheHitCounter(int $staticCacheHitCounter)
610
    {
611
        $this->staticCacheHitCounter = $staticCacheHitCounter;
612
    }
613
614
    /**
615
     * Set cache-item by key => value + date.
616
     *
617
     * @param string    $key
618
     * @param mixed     $value
619
     * @param \DateTime $date <p>If the date is in the past, we will remove the existing cache-item.</p>
620
     *
621
     * @throws InvalidArgumentException <p>If the $date is in the past.</p>
622
     *
623
     * @return bool
624
     */
625 13
    public function setItemToDate(string $key, $value, \DateTime $date): bool
626
    {
627 13
        $ttl = $date->getTimestamp() - \time();
628
629 13
        if ($ttl <= 0) {
630 1
            throw new InvalidArgumentException('Date in the past.');
631
        }
632
633 12
        return $this->setItem($key, $value, $ttl);
634
    }
635
636
    /**
637
     * Set cache-item by key => value + ttl.
638
     *
639
     * @param string                 $key
640
     * @param mixed                  $value
641
     * @param \DateInterval|int|null $ttl
642
     *
643
     * @throws InvalidArgumentException
644
     *
645
     * @return bool
646
     */
647 32
    public function setItem(string $key, $value, $ttl = 0): bool
648
    {
649
        if (
650 32
            !$this->adapter instanceof iAdapter
651
            ||
652 32
            !$this->serializer instanceof iSerializer
653
        ) {
654
            return false;
655
        }
656
657 32
        $storeKey = $this->calculateStoreKey($key);
658 32
        $serialized = $this->serializer->serialize($value);
659
660
        // update static-cache, if it's exists
661 32
        if (\array_key_exists($storeKey, self::$STATIC_CACHE) === true) {
662 5
            self::$STATIC_CACHE[$storeKey] = $value;
663
        }
664
665 32
        if ($ttl) {
666 16
            if ($ttl instanceof \DateInterval) {
667
                // Converting to a TTL in seconds
668 1
                $dateTimeNow = new \DateTime('now');
669 1
                $ttl = $dateTimeNow->add($ttl)->getTimestamp() - \time();
670
            }
671
672
            // always cache the TTL time, maybe we need this later ...
673 16
            self::$STATIC_CACHE_EXPIRE[$storeKey] = ($ttl ? (int) $ttl + \time() : 0);
674
675 16
            return $this->adapter->setExpired($storeKey, $serialized, $ttl);
676
        }
677
678 16
        return $this->adapter->set($storeKey, $serialized);
679
    }
680
681
    /**
682
     * Remove a cached-item.
683
     *
684
     * @param string $key
685
     *
686
     * @return bool
687
     */
688 5
    public function removeItem(string $key): bool
689
    {
690 5
        if (!$this->adapter instanceof iAdapter) {
691
            return false;
692
        }
693
694 5
        $storeKey = $this->calculateStoreKey($key);
695
696
        // remove static-cache
697
        if (
698 5
            !empty(self::$STATIC_CACHE)
699
            &&
700 5
            \array_key_exists($storeKey, self::$STATIC_CACHE) === true
701
        ) {
702
             unset(self::$STATIC_CACHE[$storeKey], self::$STATIC_CACHE_COUNTER[$storeKey], self::$STATIC_CACHE_EXPIRE[$storeKey]
703
            );
704
        }
705
706 5
        return $this->adapter->remove($storeKey);
707
    }
708
709
    /**
710
     * Remove all cached-items.
711
     *
712
     * @return bool
713
     */
714 3
    public function removeAll(): bool
715
    {
716 3
        if (!$this->adapter instanceof iAdapter) {
717
            return false;
718
        }
719
720
        // remove static-cache
721 3
        if (!empty(self::$STATIC_CACHE)) {
722 3
            self::$STATIC_CACHE = [];
723 3
            self::$STATIC_CACHE_COUNTER = [];
724 3
            self::$STATIC_CACHE_EXPIRE = [];
725
        }
726
727 3
        return $this->adapter->removeAll();
728
    }
729
730
    /**
731
     * Check if cached-item exists.
732
     *
733
     * @param string $key
734
     *
735
     * @return bool
736
     */
737 11
    public function existsItem(string $key): bool
738
    {
739 11
        if (!$this->adapter instanceof iAdapter) {
740
            return false;
741
        }
742
743 11
        $storeKey = $this->calculateStoreKey($key);
744
745
        // check static-cache
746 11
        if ($this->checkForStaticCache($storeKey) === true) {
747
            return true;
748
        }
749
750 11
        return $this->adapter->exists($storeKey);
751
    }
752
753
    /**
754
     * @param string $storeKey
755
     *
756
     * @return bool
757
     */
758 36
    protected function checkForStaticCache(string $storeKey): bool
759
    {
760 36
        return !empty(self::$STATIC_CACHE)
761
               &&
762 36
               \array_key_exists($storeKey, self::$STATIC_CACHE) === true
763
               &&
764 36
               \array_key_exists($storeKey, self::$STATIC_CACHE_EXPIRE) === true
765
               &&
766 36
               \time() <= self::$STATIC_CACHE_EXPIRE[$storeKey];
767
    }
768
769
    /**
770
     * Get the current adapter class-name.
771
     *
772
     * @return string
773
     */
774 3
    public function getUsedAdapterClassName(): string
775
    {
776 3
        if ($this->adapter) {
777
            /** @noinspection GetClassUsageInspection */
778 3
            return \get_class($this->adapter);
779
        }
780
781
        return '';
782
    }
783
784
    /**
785
     * Get the current serializer class-name.
786
     *
787
     * @return string
788
     */
789 3
    public function getUsedSerializerClassName(): string
790
    {
791 3
        if ($this->serializer) {
792
            /** @noinspection GetClassUsageInspection */
793 3
            return \get_class($this->serializer);
794
        }
795
796
        return '';
797
    }
798
}
799