ApcuTrait.php 3.1 KB

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