DebugHelper.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. namespace dokuwiki\Debug;
  3. use Doku_Event;
  4. use dokuwiki\Extension\EventHandler;
  5. use dokuwiki\Logger;
  6. class DebugHelper
  7. {
  8. const INFO_DEPRECATION_LOG_EVENT = 'INFO_DEPRECATION_LOG';
  9. /**
  10. * Check if deprecation messages shall be handled
  11. *
  12. * This is either because its logging is not disabled or a deprecation handler was registered
  13. *
  14. * @return bool
  15. */
  16. public static function isEnabled()
  17. {
  18. /** @var EventHandler $EVENT_HANDLER */
  19. global $EVENT_HANDLER;
  20. if (
  21. !Logger::getInstance(Logger::LOG_DEPRECATED)->isLogging() &&
  22. ($EVENT_HANDLER === null || !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG'))
  23. ) {
  24. // avoid any work if no one cares
  25. return false;
  26. }
  27. return true;
  28. }
  29. /**
  30. * Log accesses to deprecated fucntions to the debug log
  31. *
  32. * @param string $alternative (optional) The function or method that should be used instead
  33. * @param int $callerOffset (optional) How far the deprecated method is removed from this one
  34. * @param string $thing (optional) The deprecated thing, defaults to the calling method
  35. * @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
  36. */
  37. public static function dbgDeprecatedFunction($alternative = '', $callerOffset = 1, $thing = '')
  38. {
  39. if (!self::isEnabled()) return;
  40. $backtrace = debug_backtrace();
  41. for ($i = 0; $i < $callerOffset; $i += 1) {
  42. if(count($backtrace) > 1) array_shift($backtrace);
  43. }
  44. list($self, $call) = $backtrace;
  45. if (!$thing) {
  46. $thing = trim(
  47. (!empty($self['class']) ? ($self['class'] . '::') : '') .
  48. $self['function'] . '()', ':');
  49. }
  50. self::triggerDeprecationEvent(
  51. $backtrace,
  52. $alternative,
  53. $thing,
  54. trim(
  55. (!empty($call['class']) ? ($call['class'] . '::') : '') .
  56. $call['function'] . '()', ':'),
  57. $self['file'] ?? $call['file'] ?? '',
  58. $self['line'] ?? $call['line'] ?? 0
  59. );
  60. }
  61. /**
  62. * This marks logs a deprecation warning for a property that should no longer be used
  63. *
  64. * This is usually called withing a magic getter or setter.
  65. * For logging deprecated functions or methods see dbgDeprecatedFunction()
  66. *
  67. * @param string $class The class with the deprecated property
  68. * @param string $propertyName The name of the deprecated property
  69. *
  70. * @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
  71. */
  72. public static function dbgDeprecatedProperty($class, $propertyName)
  73. {
  74. if (!self::isEnabled()) return;
  75. $backtrace = debug_backtrace();
  76. array_shift($backtrace);
  77. $call = $backtrace[1];
  78. $caller = trim($call['class'] . '::' . $call['function'] . '()', ':');
  79. $qualifiedName = $class . '::$' . $propertyName;
  80. self::triggerDeprecationEvent(
  81. $backtrace,
  82. '',
  83. $qualifiedName,
  84. $caller,
  85. $backtrace[0]['file'],
  86. $backtrace[0]['line']
  87. );
  88. }
  89. /**
  90. * Trigger a custom deprecation event
  91. *
  92. * Usually dbgDeprecatedFunction() or dbgDeprecatedProperty() should be used instead.
  93. * This method is intended only for those situation where they are not applicable.
  94. *
  95. * @param string $alternative
  96. * @param string $deprecatedThing
  97. * @param string $caller
  98. * @param string $file
  99. * @param int $line
  100. * @param int $callerOffset How many lines should be removed from the beginning of the backtrace
  101. */
  102. public static function dbgCustomDeprecationEvent(
  103. $alternative,
  104. $deprecatedThing,
  105. $caller,
  106. $file,
  107. $line,
  108. $callerOffset = 1
  109. )
  110. {
  111. if (!self::isEnabled()) return;
  112. $backtrace = array_slice(debug_backtrace(), $callerOffset);
  113. self::triggerDeprecationEvent(
  114. $backtrace,
  115. $alternative,
  116. $deprecatedThing,
  117. $caller,
  118. $file,
  119. $line
  120. );
  121. }
  122. /**
  123. * @param array $backtrace
  124. * @param string $alternative
  125. * @param string $deprecatedThing
  126. * @param string $caller
  127. * @param string $file
  128. * @param int $line
  129. */
  130. private static function triggerDeprecationEvent(
  131. array $backtrace,
  132. $alternative,
  133. $deprecatedThing,
  134. $caller,
  135. $file,
  136. $line
  137. )
  138. {
  139. $data = [
  140. 'trace' => $backtrace,
  141. 'alternative' => $alternative,
  142. 'called' => $deprecatedThing,
  143. 'caller' => $caller,
  144. 'file' => $file,
  145. 'line' => $line,
  146. ];
  147. $event = new Doku_Event(self::INFO_DEPRECATION_LOG_EVENT, $data);
  148. if ($event->advise_before()) {
  149. $msg = $event->data['called'] . ' is deprecated. It was called from ';
  150. $msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
  151. if ($event->data['alternative']) {
  152. $msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
  153. }
  154. Logger::getInstance(Logger::LOG_DEPRECATED)->log($msg);
  155. }
  156. $event->advise_after();
  157. }
  158. }