Predis.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <?php
  2. /**
  3. * Predis client specific implementation.
  4. */
  5. class Redis_Client_Predis implements Redis_Client_FactoryInterface {
  6. /**
  7. * Circular depedency breaker.
  8. */
  9. static protected $autoloaderRegistered = false;
  10. /**
  11. * If the first cache get operation happens after the core autoloader has
  12. * been registered to PHP, during our autoloader registration we will
  13. * trigger it when calling class_exists(): core autoloader will then run
  14. * cache_get() during autoloading but sadly this will run our autoloader
  15. * registration once again. The second time we are called the circular
  16. * dependency breaker will act and we will do nothing, ending up in a
  17. * class instanciation attempt while the autoloader is still not loaded.
  18. */
  19. static protected $stupidCoreWorkaround = 0;
  20. /**
  21. * Define Predis base path if not already set, and if we need to set the
  22. * autoloader by ourself. This will ensure no crash. Best way would have
  23. * been that Drupal ships a PSR-0 autoloader, in which we could manually
  24. * add our library path.
  25. *
  26. * We cannot do that in the file header, PHP class_exists() function wont
  27. * see classes being loaded during the autoloading because this file is
  28. * loaded by another autoloader: attempting the class_exists() during a
  29. * pending autoloading would cause PHP to crash and ignore the rest of the
  30. * file silentely (WTF!?). By delaying this at the getClient() call we
  31. * ensure we are not in the class loading process anymore.
  32. */
  33. public static function setPredisAutoload() {
  34. if (self::$autoloaderRegistered) {
  35. return;
  36. }
  37. self::$stupidCoreWorkaround++;
  38. // If you attempt to set Drupal's bin cache_bootstrap using Redis, you
  39. // will experience an infinite loop (breaking by itself the second time
  40. // it passes by): the following call will wake up autoloaders (and we
  41. // want that to work since user may have set its own autoloader) but
  42. // will wake up Drupal's one too, and because Drupal core caches its
  43. // file map, this will trigger this method to be called a second time
  44. // and boom! Adios bye bye. That's why this will be called early in the
  45. // 'redis.autoload.inc' file instead.
  46. if (1 < self::$stupidCoreWorkaround || !class_exists('Predis\Client')) {
  47. if (!defined('PREDIS_BASE_PATH')) {
  48. $search = DRUPAL_ROOT . '/sites/all/libraries/predis';
  49. define('PREDIS_BASE_PATH', $search);
  50. } else {
  51. $search = PREDIS_BASE_PATH;
  52. }
  53. if (is_dir($search . '/src')) { // Predis v1.x
  54. define('PREDIS_VERSION_MAJOR', 1);
  55. } else if (is_dir($search . '/lib')) { // Predis v0.x
  56. define('PREDIS_VERSION_MAJOR', 0);
  57. } else {
  58. throw new Exception("PREDIS_BASE_PATH constant must be set, Predis library must live in sites/all/libraries/predis.");
  59. }
  60. // Register a simple autoloader for Predis library. Since the Predis
  61. // library is PHP 5.3 only, we can afford doing closures safely.
  62. switch (PREDIS_VERSION_MAJOR) {
  63. case 0:
  64. $autoload = function($classname) { // PSR-0 autoloader.
  65. if (0 === strpos($classname, 'Predis\\')) {
  66. $filename = PREDIS_BASE_PATH . '/lib/' . str_replace('\\', '/', $classname) . '.php';
  67. return (bool)require_once $filename;
  68. }
  69. return false;
  70. };
  71. break;
  72. case 1:
  73. // Register a simple autoloader for Predis library. Since the Predis
  74. // library is PHP 5.3 only, we can afford doing closures safely.
  75. $autoload = function($classname) { // PSR-4 autoloader
  76. if (0 === strpos($classname, 'Predis\\')) {
  77. $filename = PREDIS_BASE_PATH . '/src/' . str_replace('\\', '/', substr($classname, 7)) . '.php';
  78. return (bool)require_once $filename;
  79. }
  80. return false;
  81. };
  82. break;
  83. }
  84. if ($autoload) {
  85. spl_autoload_register($autoload);
  86. }
  87. // Same reason why we have the stupid core workaround, if this happens
  88. // during a second autoload call, PHP won't call the newly registered
  89. // autoloader function, so just load the file.
  90. if (1 < self::$stupidCoreWorkaround) {
  91. call_user_func($autoload, 'Predis\Client');
  92. }
  93. }
  94. self::$autoloaderRegistered = true;
  95. }
  96. public function getClient($options = array()) {
  97. self::setPredisAutoload();
  98. if (!empty($options['socket'])) {
  99. $options['scheme'] = 'unix';
  100. $options['path'] = $options['socket'];
  101. }
  102. foreach ($options as $key => $value) {
  103. if (!isset($value)) {
  104. unset($options[$key]);
  105. }
  106. }
  107. // I'm not sure why but the error handler is driven crazy if timezone
  108. // is not set at this point.
  109. // Hopefully Drupal will restore the right one this once the current
  110. // account has logged in.
  111. date_default_timezone_set(@date_default_timezone_get());
  112. $client = new \Predis\Client($options);
  113. if (isset($options['base']) && 0 !== $options['base']) {
  114. $client->select((int)$options['base']);
  115. }
  116. return $client;
  117. }
  118. public function getName() {
  119. return 'Predis';
  120. }
  121. }