PhpFileCache.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. namespace Doctrine\Common\Cache;
  3. use function is_object;
  4. use function method_exists;
  5. use function restore_error_handler;
  6. use function serialize;
  7. use function set_error_handler;
  8. use function sprintf;
  9. use function time;
  10. use function var_export;
  11. /**
  12. * Php file cache driver.
  13. */
  14. class PhpFileCache extends FileCache
  15. {
  16. public const EXTENSION = '.doctrinecache.php';
  17. /**
  18. * @var callable
  19. *
  20. * This is cached in a local static variable to avoid instantiating a closure each time we need an empty handler
  21. */
  22. private static $emptyErrorHandler;
  23. /**
  24. * {@inheritdoc}
  25. */
  26. public function __construct($directory, $extension = self::EXTENSION, $umask = 0002)
  27. {
  28. parent::__construct($directory, $extension, $umask);
  29. self::$emptyErrorHandler = static function () {
  30. };
  31. }
  32. /**
  33. * {@inheritdoc}
  34. */
  35. protected function doFetch($id)
  36. {
  37. $value = $this->includeFileForId($id);
  38. if ($value === null) {
  39. return false;
  40. }
  41. if ($value['lifetime'] !== 0 && $value['lifetime'] < time()) {
  42. return false;
  43. }
  44. return $value['data'];
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. protected function doContains($id)
  50. {
  51. $value = $this->includeFileForId($id);
  52. if ($value === null) {
  53. return false;
  54. }
  55. return $value['lifetime'] === 0 || $value['lifetime'] > time();
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. protected function doSave($id, $data, $lifeTime = 0)
  61. {
  62. if ($lifeTime > 0) {
  63. $lifeTime = time() + $lifeTime;
  64. }
  65. $filename = $this->getFilename($id);
  66. $value = [
  67. 'lifetime' => $lifeTime,
  68. 'data' => $data,
  69. ];
  70. if (is_object($data) && method_exists($data, '__set_state')) {
  71. $value = var_export($value, true);
  72. $code = sprintf('<?php return %s;', $value);
  73. } else {
  74. $value = var_export(serialize($value), true);
  75. $code = sprintf('<?php return unserialize(%s);', $value);
  76. }
  77. return $this->writeFile($filename, $code);
  78. }
  79. /**
  80. * @return array|null
  81. */
  82. private function includeFileForId(string $id) : ?array
  83. {
  84. $fileName = $this->getFilename($id);
  85. // note: error suppression is still faster than `file_exists`, `is_file` and `is_readable`
  86. set_error_handler(self::$emptyErrorHandler);
  87. $value = include $fileName;
  88. restore_error_handler();
  89. if (! isset($value['lifetime'])) {
  90. return null;
  91. }
  92. return $value;
  93. }
  94. }