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