You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

179 lines
5.4 KiB

  1. <?php
  2. namespace dokuwiki\Debug;
  3. use dokuwiki\Extension\Event;
  4. use dokuwiki\Extension\EventHandler;
  5. use dokuwiki\Logger;
  6. class DebugHelper
  7. {
  8. protected 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 instanceof EventHandler || !$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) {
  42. if (count($backtrace) > 1) array_shift($backtrace);
  43. }
  44. [$self, $call] = $backtrace;
  45. self::triggerDeprecationEvent(
  46. $backtrace,
  47. $alternative,
  48. self::formatCall($self),
  49. self::formatCall($call),
  50. $self['file'] ?? $call['file'] ?? '',
  51. $self['line'] ?? $call['line'] ?? 0
  52. );
  53. }
  54. /**
  55. * Format the given backtrace info into a proper function/method call string
  56. * @param array $call
  57. * @return string
  58. */
  59. protected static function formatCall($call)
  60. {
  61. $thing = '';
  62. if (!empty($call['class'])) {
  63. $thing .= $call['class'] . '::';
  64. }
  65. $thing .= $call['function'] . '()';
  66. return trim($thing, ':');
  67. }
  68. /**
  69. * This marks logs a deprecation warning for a property that should no longer be used
  70. *
  71. * This is usually called withing a magic getter or setter.
  72. * For logging deprecated functions or methods see dbgDeprecatedFunction()
  73. *
  74. * @param string $class The class with the deprecated property
  75. * @param string $propertyName The name of the deprecated property
  76. *
  77. * @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
  78. */
  79. public static function dbgDeprecatedProperty($class, $propertyName)
  80. {
  81. if (!self::isEnabled()) return;
  82. $backtrace = debug_backtrace();
  83. array_shift($backtrace);
  84. $call = $backtrace[1];
  85. $caller = trim($call['class'] . '::' . $call['function'] . '()', ':');
  86. $qualifiedName = $class . '::$' . $propertyName;
  87. self::triggerDeprecationEvent(
  88. $backtrace,
  89. '',
  90. $qualifiedName,
  91. $caller,
  92. $backtrace[0]['file'],
  93. $backtrace[0]['line']
  94. );
  95. }
  96. /**
  97. * Trigger a custom deprecation event
  98. *
  99. * Usually dbgDeprecatedFunction() or dbgDeprecatedProperty() should be used instead.
  100. * This method is intended only for those situation where they are not applicable.
  101. *
  102. * @param string $alternative
  103. * @param string $deprecatedThing
  104. * @param string $caller
  105. * @param string $file
  106. * @param int $line
  107. * @param int $callerOffset How many lines should be removed from the beginning of the backtrace
  108. */
  109. public static function dbgCustomDeprecationEvent(
  110. $alternative,
  111. $deprecatedThing,
  112. $caller,
  113. $file,
  114. $line,
  115. $callerOffset = 1
  116. ) {
  117. if (!self::isEnabled()) return;
  118. $backtrace = array_slice(debug_backtrace(), $callerOffset);
  119. self::triggerDeprecationEvent(
  120. $backtrace,
  121. $alternative,
  122. $deprecatedThing,
  123. $caller,
  124. $file,
  125. $line
  126. );
  127. }
  128. /**
  129. * @param array $backtrace
  130. * @param string $alternative
  131. * @param string $deprecatedThing
  132. * @param string $caller
  133. * @param string $file
  134. * @param int $line
  135. */
  136. private static function triggerDeprecationEvent(
  137. array $backtrace,
  138. $alternative,
  139. $deprecatedThing,
  140. $caller,
  141. $file,
  142. $line
  143. ) {
  144. $data = [
  145. 'trace' => $backtrace,
  146. 'alternative' => $alternative,
  147. 'called' => $deprecatedThing,
  148. 'caller' => $caller,
  149. 'file' => $file,
  150. 'line' => $line,
  151. ];
  152. $event = new Event(self::INFO_DEPRECATION_LOG_EVENT, $data);
  153. if ($event->advise_before()) {
  154. $msg = $event->data['called'] . ' is deprecated. It was called from ';
  155. $msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
  156. if ($event->data['alternative']) {
  157. $msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
  158. }
  159. Logger::getInstance(Logger::LOG_DEPRECATED)->log($msg);
  160. }
  161. $event->advise_after();
  162. }
  163. }