xref: /dokuwiki/inc/Debug/DebugHelper.php (revision 31add35e59dd9c120f6ec809ce96e83b28526907)
10c5eb5e2SMichael Große<?php
20c5eb5e2SMichael Große
30c5eb5e2SMichael Großenamespace dokuwiki\Debug;
40c5eb5e2SMichael Große
58553d24dSAndreas Gohruse dokuwiki\Extension\Event;
6e1d9dcc8SAndreas Gohruse dokuwiki\Extension\EventHandler;
70ecde6ceSAndreas Gohruse dokuwiki\Logger;
80c5eb5e2SMichael Große
90c5eb5e2SMichael Großeclass DebugHelper
100c5eb5e2SMichael Große{
1174981a4eSAndreas Gohr    protected const INFO_DEPRECATION_LOG_EVENT = 'INFO_DEPRECATION_LOG';
120c5eb5e2SMichael Große
130c5eb5e2SMichael Große    /**
1425edeecaSAndreas Gohr     * Check if deprecation messages shall be handled
1525edeecaSAndreas Gohr     *
1625edeecaSAndreas Gohr     * This is either because its logging is not disabled or a deprecation handler was registered
1725edeecaSAndreas Gohr     *
1825edeecaSAndreas Gohr     * @return bool
1925edeecaSAndreas Gohr     */
2025edeecaSAndreas Gohr    public static function isEnabled()
2125edeecaSAndreas Gohr    {
2225edeecaSAndreas Gohr        /** @var EventHandler $EVENT_HANDLER */
2325edeecaSAndreas Gohr        global $EVENT_HANDLER;
2425edeecaSAndreas Gohr        if (
2525edeecaSAndreas Gohr            !Logger::getInstance(Logger::LOG_DEPRECATED)->isLogging() &&
261490c177SAndreas Gohr            (!$EVENT_HANDLER instanceof EventHandler || !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG'))
2725edeecaSAndreas Gohr        ) {
2825edeecaSAndreas Gohr            // avoid any work if no one cares
2925edeecaSAndreas Gohr            return false;
3025edeecaSAndreas Gohr        }
3125edeecaSAndreas Gohr        return true;
3225edeecaSAndreas Gohr    }
3325edeecaSAndreas Gohr
3425edeecaSAndreas Gohr    /**
350c5eb5e2SMichael Große     * Log accesses to deprecated fucntions to the debug log
360c5eb5e2SMichael Große     *
370c5eb5e2SMichael Große     * @param string $alternative (optional) The function or method that should be used instead
380c5eb5e2SMichael Große     * @param int $callerOffset (optional) How far the deprecated method is removed from this one
39e4aa0139SAndreas Gohr     * @param string $thing (optional) The deprecated thing, defaults to the calling method
400c5eb5e2SMichael Große     * @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
410c5eb5e2SMichael Große     */
42e4aa0139SAndreas Gohr    public static function dbgDeprecatedFunction($alternative = '', $callerOffset = 1, $thing = '')
430c5eb5e2SMichael Große    {
4425edeecaSAndreas Gohr        if (!self::isEnabled()) return;
450c5eb5e2SMichael Große
460c5eb5e2SMichael Große        $backtrace = debug_backtrace();
471490c177SAndreas Gohr        for ($i = 0; $i < $callerOffset; ++$i) {
48c0ece86aSAndreas Gohr            if (count($backtrace) > 1) array_shift($backtrace);
490c5eb5e2SMichael Große        }
500c5eb5e2SMichael Große
511490c177SAndreas Gohr        [$self, $call] = $backtrace;
520c5eb5e2SMichael Große
530c5eb5e2SMichael Große        self::triggerDeprecationEvent(
540c5eb5e2SMichael Große            $backtrace,
550c5eb5e2SMichael Große            $alternative,
56*31add35eSAndreas Gohr            $thing ?: self::formatCall($self),
57615810c5SAndreas Gohr            self::formatCall($call),
58c243774dSAndreas Gohr            $self['file'] ?? $call['file'] ?? '',
59c243774dSAndreas Gohr            $self['line'] ?? $call['line'] ?? 0
600c5eb5e2SMichael Große        );
610c5eb5e2SMichael Große    }
620c5eb5e2SMichael Große
630c5eb5e2SMichael Große    /**
64615810c5SAndreas Gohr     * Format the given backtrace info into a proper function/method call string
65615810c5SAndreas Gohr     * @param array $call
66615810c5SAndreas Gohr     * @return string
67615810c5SAndreas Gohr     */
68615810c5SAndreas Gohr    protected static function formatCall($call)
69615810c5SAndreas Gohr    {
70615810c5SAndreas Gohr        $thing = '';
71615810c5SAndreas Gohr        if (!empty($call['class'])) {
72615810c5SAndreas Gohr            $thing .= $call['class'] . '::';
73615810c5SAndreas Gohr        }
74615810c5SAndreas Gohr        $thing .= $call['function'] . '()';
75615810c5SAndreas Gohr        return trim($thing, ':');
76615810c5SAndreas Gohr    }
77615810c5SAndreas Gohr
78615810c5SAndreas Gohr    /**
790c5eb5e2SMichael Große     * This marks logs a deprecation warning for a property that should no longer be used
800c5eb5e2SMichael Große     *
810c5eb5e2SMichael Große     * This is usually called withing a magic getter or setter.
820c5eb5e2SMichael Große     * For logging deprecated functions or methods see dbgDeprecatedFunction()
830c5eb5e2SMichael Große     *
840c5eb5e2SMichael Große     * @param string $class The class with the deprecated property
850c5eb5e2SMichael Große     * @param string $propertyName The name of the deprecated property
860c5eb5e2SMichael Große     *
870c5eb5e2SMichael Große     * @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
880c5eb5e2SMichael Große     */
890c5eb5e2SMichael Große    public static function dbgDeprecatedProperty($class, $propertyName)
900c5eb5e2SMichael Große    {
9125edeecaSAndreas Gohr        if (!self::isEnabled()) return;
920c5eb5e2SMichael Große
930c5eb5e2SMichael Große        $backtrace = debug_backtrace();
940c5eb5e2SMichael Große        array_shift($backtrace);
950c5eb5e2SMichael Große        $call = $backtrace[1];
960c5eb5e2SMichael Große        $caller = trim($call['class'] . '::' . $call['function'] . '()', ':');
970c5eb5e2SMichael Große        $qualifiedName = $class . '::$' . $propertyName;
980c5eb5e2SMichael Große        self::triggerDeprecationEvent(
990c5eb5e2SMichael Große            $backtrace,
1000c5eb5e2SMichael Große            '',
1010c5eb5e2SMichael Große            $qualifiedName,
1020c5eb5e2SMichael Große            $caller,
1030c5eb5e2SMichael Große            $backtrace[0]['file'],
1040c5eb5e2SMichael Große            $backtrace[0]['line']
1050c5eb5e2SMichael Große        );
1060c5eb5e2SMichael Große    }
1070c5eb5e2SMichael Große
1080c5eb5e2SMichael Große    /**
1091b008e87SMichael Große     * Trigger a custom deprecation event
1101b008e87SMichael Große     *
1111b008e87SMichael Große     * Usually dbgDeprecatedFunction() or dbgDeprecatedProperty() should be used instead.
1121b008e87SMichael Große     * This method is intended only for those situation where they are not applicable.
1131b008e87SMichael Große     *
1141b008e87SMichael Große     * @param string $alternative
1151b008e87SMichael Große     * @param string $deprecatedThing
1161b008e87SMichael Große     * @param string $caller
1171b008e87SMichael Große     * @param string $file
1181b008e87SMichael Große     * @param int $line
1191b008e87SMichael Große     * @param int $callerOffset How many lines should be removed from the beginning of the backtrace
1201b008e87SMichael Große     */
1211b008e87SMichael Große    public static function dbgCustomDeprecationEvent(
1221b008e87SMichael Große        $alternative,
1231b008e87SMichael Große        $deprecatedThing,
1241b008e87SMichael Große        $caller,
1251b008e87SMichael Große        $file,
1261b008e87SMichael Große        $line,
1271b008e87SMichael Große        $callerOffset = 1
128d868eb89SAndreas Gohr    ) {
12925edeecaSAndreas Gohr        if (!self::isEnabled()) return;
1301b008e87SMichael Große
1311b008e87SMichael Große        $backtrace = array_slice(debug_backtrace(), $callerOffset);
1321b008e87SMichael Große
1331b008e87SMichael Große        self::triggerDeprecationEvent(
1341b008e87SMichael Große            $backtrace,
1351b008e87SMichael Große            $alternative,
1361b008e87SMichael Große            $deprecatedThing,
1371b008e87SMichael Große            $caller,
1381b008e87SMichael Große            $file,
1391b008e87SMichael Große            $line
1401b008e87SMichael Große        );
1411b008e87SMichael Große    }
1421b008e87SMichael Große
1431b008e87SMichael Große    /**
1440c5eb5e2SMichael Große     * @param array $backtrace
1450c5eb5e2SMichael Große     * @param string $alternative
1460c5eb5e2SMichael Große     * @param string $deprecatedThing
1470c5eb5e2SMichael Große     * @param string $caller
1480c5eb5e2SMichael Große     * @param string $file
1490c5eb5e2SMichael Große     * @param int $line
1500c5eb5e2SMichael Große     */
1510c5eb5e2SMichael Große    private static function triggerDeprecationEvent(
1520c5eb5e2SMichael Große        array $backtrace,
1530c5eb5e2SMichael Große        $alternative,
1540c5eb5e2SMichael Große        $deprecatedThing,
1550c5eb5e2SMichael Große        $caller,
1560c5eb5e2SMichael Große        $file,
1570c5eb5e2SMichael Große        $line
158d868eb89SAndreas Gohr    ) {
1590c5eb5e2SMichael Große        $data = [
1600c5eb5e2SMichael Große            'trace' => $backtrace,
1610c5eb5e2SMichael Große            'alternative' => $alternative,
1620c5eb5e2SMichael Große            'called' => $deprecatedThing,
1630c5eb5e2SMichael Große            'caller' => $caller,
1640c5eb5e2SMichael Große            'file' => $file,
1650c5eb5e2SMichael Große            'line' => $line,
1660c5eb5e2SMichael Große        ];
1678553d24dSAndreas Gohr        $event = new Event(self::INFO_DEPRECATION_LOG_EVENT, $data);
1680c5eb5e2SMichael Große        if ($event->advise_before()) {
1690c5eb5e2SMichael Große            $msg = $event->data['called'] . ' is deprecated. It was called from ';
1700c5eb5e2SMichael Große            $msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
1710c5eb5e2SMichael Große            if ($event->data['alternative']) {
1720c5eb5e2SMichael Große                $msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
1730c5eb5e2SMichael Große            }
1740ecde6ceSAndreas Gohr            Logger::getInstance(Logger::LOG_DEPRECATED)->log($msg);
1750c5eb5e2SMichael Große        }
1760c5eb5e2SMichael Große        $event->advise_after();
1770c5eb5e2SMichael Große    }
1780c5eb5e2SMichael Große}
179