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