Moved warning stuff into MWDebug class.
authorAlexandre Emsenhuber <ialex.wiki@gmail.com>
Sat, 25 Aug 2012 11:09:46 +0000 (13:09 +0200)
committerAlexandre Emsenhuber <ialex.wiki@gmail.com>
Tue, 28 Aug 2012 13:33:44 +0000 (15:33 +0200)
- Group common code in one instead of doing checks one
  time in GlobalFunctions.php and another time in Debug.php
- Remove the code catching the fact that a warning is due
  to a deprecation warning, no longer needed
- Pass the caller offset from wfDeprecated() to
  MWDebug::deprecated(); this was breaking deprecation
  notices for global objects.
- Changed PHP error level for deprecation notices (when
  $wgDevelopmentWarnings is set to true) from E_USER_NOTICE
  to E_USER_DEPRECATED since we now require PHP 5.3+
- Added E_USER_DEPRECATED to wfSuppressWarnings() and
  removed the check for the E_DEPRECATED constant being set
  now that we require PHP 5.3+
- Fixed MWDebugTest by calling wfSuppressWarnings() and
  wfRestoreWarnings() in setUp() and tearDown()

Change-Id: I6810b57c90d384de55a2cf177047767cdb734f79

includes/GlobalFunctions.php
includes/debug/Debug.php
tests/phpunit/includes/debug/MWDebugTest.php

index 328d429..4ff258d 100644 (file)
@@ -1082,35 +1082,7 @@ function wfLogDBError( $text ) {
  * @return null
  */
 function wfDeprecated( $function, $version = false, $component = false, $callerOffset = 2 ) {
-       static $functionsWarned = array();
-
-       MWDebug::deprecated( $function, $version, $component );
-
-       if ( !isset( $functionsWarned[$function] ) ) {
-               $functionsWarned[$function] = true;
-
-               if ( $version ) {
-                       global $wgDeprecationReleaseLimit;
-
-                       if ( $wgDeprecationReleaseLimit && $component === false ) {
-                               # Strip -* off the end of $version so that branches can use the
-                               # format #.##-branchname to avoid issues if the branch is merged into
-                               # a version of MediaWiki later than what it was branched from
-                               $comparableVersion = preg_replace( '/-.*$/', '', $version );
-
-                               # If the comparableVersion is larger than our release limit then
-                               # skip the warning message for the deprecation
-                               if ( version_compare( $wgDeprecationReleaseLimit, $comparableVersion, '<' ) ) {
-                                       return;
-                               }
-                       }
-
-                       $component = $component === false ? 'MediaWiki' : $component;
-                       wfWarn( "Use of $function was deprecated in $component $version.", $callerOffset );
-               } else {
-                       wfWarn( "Use of $function is deprecated.", $callerOffset );
-               }
-       }
+       MWDebug::deprecated( $function, $version, $component, $callerOffset + 1 );
 }
 
 /**
@@ -1124,34 +1096,7 @@ function wfDeprecated( $function, $version = false, $component = false, $callerO
  *        is true
  */
 function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
-       global $wgDevelopmentWarnings;
-
-       MWDebug::warning( $msg, $callerOffset + 2 );
-
-       $callers = wfDebugBacktrace();
-       if ( isset( $callers[$callerOffset + 1] ) ) {
-               $callerfunc = $callers[$callerOffset + 1];
-               $callerfile = $callers[$callerOffset];
-               if ( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) {
-                       $file = $callerfile['file'] . ' at line ' . $callerfile['line'];
-               } else {
-                       $file = '(internal function)';
-               }
-               $func = '';
-               if ( isset( $callerfunc['class'] ) ) {
-                       $func .= $callerfunc['class'] . '::';
-               }
-               if ( isset( $callerfunc['function'] ) ) {
-                       $func .= $callerfunc['function'];
-               }
-               $msg .= " [Called from $func in $file]";
-       }
-
-       if ( $wgDevelopmentWarnings ) {
-               trigger_error( $msg, $level );
-       } else {
-               wfDebug( "$msg\n" );
-       }
+       MWDebug::warning( $msg, $callerOffset + 1, $level );
 }
 
 /**
@@ -2383,11 +2328,7 @@ function wfSuppressWarnings( $end = false ) {
                }
        } else {
                if ( !$suppressCount ) {
-                       // E_DEPRECATED is undefined in PHP 5.2
-                       if( !defined( 'E_DEPRECATED' ) ) {
-                               define( 'E_DEPRECATED', 8192 );
-                       }
-                       $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED ) );
+                       $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED ) );
                }
                ++$suppressCount;
        }
index 0b623e6..d02bcf5 100644 (file)
@@ -133,70 +133,156 @@ class MWDebug {
         * Adds a warning entry to the log
         *
         * @since 1.19
-        * @param $msg
-        * @param int $callerOffset
+        * @param $msg string
+        * @param $callerOffset int
         * @return mixed
         */
-       public static function warning( $msg, $callerOffset = 1 ) {
-               if ( !self::$enabled ) {
-                       return;
-               }
+       public static function warning( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
+               $callerDescription = self::getCallerDescription( $callerOffset );
 
-               // Check to see if there was already a deprecation notice, so not to
-               // get a duplicate warning
-               $logCount = count( self::$log );
-               $caller = wfGetCaller( $callerOffset + 1 );
-               if ( $logCount ) {
-                       $lastLog = self::$log[ $logCount - 1 ];
-                       if ( $lastLog['type'] == 'deprecated' && $lastLog['caller'] == $caller ) {
-                               return;
-                       }
-               }
+               self::sendWarning( $msg, $callerDescription, $level );
 
-               self::$log[] = array(
-                       'msg' => htmlspecialchars( $msg ),
-                       'type' => 'warn',
-                       'caller' => $caller,
-               );
+               if ( self::$enabled ) {
+                       self::$log[] = array(
+                               'msg' => htmlspecialchars( $msg ),
+                               'type' => 'warn',
+                               'caller' => $callerDescription['func'],
+                       );
+               }
        }
 
        /**
-        * Adds a depreciation entry to the log, along with a backtrace
+        * Show a warning that $function is deprecated.
+        * This will send it to the following locations:
+        * - Debug toolbar, with one item per function and caller, if $wgDebugToolbar
+        *   is set to true.
+        * - PHP's error log, with level E_USER_DEPRECATED, if $wgDevelopmentWarnings
+        *   is set to true.
+        * - MediaWiki's debug log, if $wgDevelopmentWarnings is set to false.
         *
         * @since 1.19
-        * @param $function
-        * @param $version
-        * @param $component
+        * @param $function string: Function that is deprecated.
+        * @param $version string|bool: Version in which the function was deprecated.
+        * @param $component string|bool: Component to which the function belongs.
+        *     If false, it is assumbed the function is in MediaWiki core.
+        * @param $callerOffset integer: How far up the callstack is the original
+        *    caller. 2 = function that called the function that called
+        *    MWDebug::deprecated() (Added in 1.20).
         * @return mixed
         */
-       public static function deprecated( $function, $version, $component ) {
-               if ( !self::$enabled ) {
-                       return;
-               }
+       public static function deprecated( $function, $version = false, $component = false, $callerOffset = 2 ) {
+               $callerDescription = self::getCallerDescription( $callerOffset );
+               $callerFunc = $callerDescription['func'];
 
-               // Chain: This function -> wfDeprecated -> deprecatedFunction -> caller
-               $caller = wfGetCaller( 4 );
+               $sendToLog = true;
 
                // Check to see if there already was a warning about this function
-               $functionString = "$function-$caller";
-               if ( in_array( $functionString, self::$deprecationWarnings ) ) {
+               if ( isset( self::$deprecationWarnings[$function][$callerFunc] ) ) {
                        return;
+               } elseif ( isset( self::$deprecationWarnings[$function] ) ) {
+                       if ( self::$enabled ) {
+                               $sendToLog = false;
+                       } else {
+                               return;
+                       }
                }
 
-               $version = $version === false ? '(unknown version)' : $version;
-               $component = $component === false ? 'MediaWiki' : $component;
-               $msg = htmlspecialchars( "Use of function $function was deprecated in $component $version" );
-               $msg .= Html::rawElement( 'div', array( 'class' => 'mw-debug-backtrace' ),
-                       Html::element( 'span', array(), 'Backtrace:' )
-                        . wfBacktrace()
-               );
+               self::$deprecationWarnings[$function][$callerFunc] = true;
 
-               self::$deprecationWarnings[] = $functionString;
-               self::$log[] = array(
-                       'msg' => $msg,
-                       'type' => 'deprecated',
-                       'caller' => $caller,
-               );
+               if ( $version ) {
+                       global $wgDeprecationReleaseLimit;
+                       if ( $wgDeprecationReleaseLimit && $component === false ) {
+                               # Strip -* off the end of $version so that branches can use the
+                               # format #.##-branchname to avoid issues if the branch is merged into
+                               # a version of MediaWiki later than what it was branched from
+                               $comparableVersion = preg_replace( '/-.*$/', '', $version );
+
+                               # If the comparableVersion is larger than our release limit then
+                               # skip the warning message for the deprecation
+                               if ( version_compare( $wgDeprecationReleaseLimit, $comparableVersion, '<' ) ) {
+                                       $sendToLog = false;
+                               }
+                       }
+
+                       $component = $component === false ? 'MediaWiki' : $component;
+                       $msg = "Use of $function was deprecated in $component $version.";
+               } else {
+                       $msg = "Use of $function is deprecated.";
+               }
+
+               if ( $sendToLog ) {
+                       self::sendWarning( $msg, $callerDescription, E_USER_DEPRECATED );
+               }
+
+               if ( self::$enabled ) {
+                       $logMsg = htmlspecialchars( $msg ) .
+                               Html::rawElement( 'div', array( 'class' => 'mw-debug-backtrace' ),
+                                       Html::element( 'span', array(), 'Backtrace:' ) . wfBacktrace()
+                               );
+
+                       self::$log[] = array(
+                               'msg' => $logMsg,
+                               'type' => 'deprecated',
+                               'caller' => $callerFunc,
+                       );
+               }
+       }
+
+       /**
+        * Get an array describing the calling function at a specified offset.
+        *
+        * @param $callerOffset integer: How far up the callstack is the original
+        *    caller. 0 = function that called getCallerDescription()
+        * @return array with two keys: 'file' and 'func'
+        */
+       private static function getCallerDescription( $callerOffset ) {
+               $callers = wfDebugBacktrace();
+
+               if ( isset( $callers[$callerOffset] ) ) {
+                       $callerfile = $callers[$callerOffset];
+                       if ( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) {
+                               $file = $callerfile['file'] . ' at line ' . $callerfile['line'];
+                       } else {
+                               $file = '(internal function)';
+                       }
+               } else {
+                       $file = '(unknown location)';
+               }
+
+               if ( isset( $callers[$callerOffset + 1] ) ) {
+                       $callerfunc = $callers[$callerOffset + 1];
+                       $func = '';
+                       if ( isset( $callerfunc['class'] ) ) {
+                               $func .= $callerfunc['class'] . '::';
+                       }
+                       if ( isset( $callerfunc['function'] ) ) {
+                               $func .= $callerfunc['function'];
+                       }
+               } else {
+                       $func = 'unknown';
+               }
+
+               return array( 'file' => $file, 'func' => $func );
+       }
+
+       /**
+        * Send a warning either to the debug log or by triggering an user PHP
+        * error depending on $wgDevelopmentWarnings.
+        *
+        * @param $msg string Message to send
+        * @param $caller array caller description get from getCallerDescription()
+        * @param $level error level to use if $wgDevelopmentWarnings is true
+        */
+       private static function sendWarning( $msg, $caller, $level ) {
+               global $wgDevelopmentWarnings;
+
+               $msg .= ' [Called from ' . $caller['func'] . ' in ' . $caller['file'] . ']';
+
+               if ( $wgDevelopmentWarnings ) {
+                       trigger_error( $msg, $level );
+               } else {
+                       wfDebug( "$msg\n" );
+               }
        }
 
        /**
index 1627c47..246b291 100644 (file)
@@ -12,6 +12,11 @@ class MWDebugTest extends MediaWikiTestCase {
                }
                /** Clear log before each test */
                MWDebug::clearLog();
+               wfSuppressWarnings();
+       }
+
+       function tearDown() {
+               wfRestoreWarnings();
        }
 
        function testAddLog() {