ApcuAdapter.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Cache\Adapter;
  11. use Symfony\Component\Cache\CacheItem;
  12. use Symfony\Component\Cache\Exception\CacheException;
  13. /**
  14. * @author Nicolas Grekas <p@tchwork.com>
  15. */
  16. class ApcuAdapter extends AbstractAdapter
  17. {
  18. /**
  19. * @throws CacheException if APCu is not enabled
  20. */
  21. public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null)
  22. {
  23. if (!static::isSupported()) {
  24. throw new CacheException('APCu is not enabled.');
  25. }
  26. if ('cli' === \PHP_SAPI) {
  27. ini_set('apc.use_request_time', 0);
  28. }
  29. parent::__construct($namespace, $defaultLifetime);
  30. if (null !== $version) {
  31. CacheItem::validateKey($version);
  32. if (!apcu_exists($version.'@'.$namespace)) {
  33. $this->doClear($namespace);
  34. apcu_add($version.'@'.$namespace, null);
  35. }
  36. }
  37. }
  38. public static function isSupported()
  39. {
  40. return \function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN);
  41. }
  42. /**
  43. * {@inheritdoc}
  44. */
  45. protected function doFetch(array $ids)
  46. {
  47. $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
  48. try {
  49. $values = [];
  50. foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) {
  51. if (null !== $v || $ok) {
  52. $values[$k] = $v;
  53. }
  54. }
  55. return $values;
  56. } catch (\Error $e) {
  57. throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
  58. } finally {
  59. ini_set('unserialize_callback_func', $unserializeCallbackHandler);
  60. }
  61. }
  62. /**
  63. * {@inheritdoc}
  64. */
  65. protected function doHave(string $id)
  66. {
  67. return apcu_exists($id);
  68. }
  69. /**
  70. * {@inheritdoc}
  71. */
  72. protected function doClear(string $namespace)
  73. {
  74. return isset($namespace[0]) && class_exists(\APCuIterator::class, false) && ('cli' !== \PHP_SAPI || filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))
  75. ? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY))
  76. : apcu_clear_cache();
  77. }
  78. /**
  79. * {@inheritdoc}
  80. */
  81. protected function doDelete(array $ids)
  82. {
  83. foreach ($ids as $id) {
  84. apcu_delete($id);
  85. }
  86. return true;
  87. }
  88. /**
  89. * {@inheritdoc}
  90. */
  91. protected function doSave(array $values, int $lifetime)
  92. {
  93. try {
  94. if (false === $failures = apcu_store($values, null, $lifetime)) {
  95. $failures = $values;
  96. }
  97. return array_keys($failures);
  98. } catch (\Throwable $e) {
  99. if (1 === \count($values)) {
  100. // Workaround https://github.com/krakjoe/apcu/issues/170
  101. apcu_delete(key($values));
  102. }
  103. throw $e;
  104. }
  105. }
  106. }