Various documentation updates for includes/parser/
[lhc/web/wiklou.git] / includes / parser / Parser.php
index 6818884..11a73f3 100644 (file)
@@ -119,102 +119,206 @@ class Parser {
        const TOC_START = '<mw:toc>';
        const TOC_END = '</mw:toc>';
 
-       # Persistent:
-       var $mTagHooks = array();
-       var $mTransparentTagHooks = array();
-       var $mFunctionHooks = array();
-       var $mFunctionSynonyms = array( 0 => array(), 1 => array() );
-       var $mFunctionTagHooks = array();
-       var $mStripList = array();
-       var $mDefaultStripList = array();
-       var $mVarCache = array();
-       var $mImageParams = array();
-       var $mImageParamsMagicArray = array();
-       var $mMarkerIndex = 0;
-       var $mFirstCall = true;
+       # Persistent
 
-       # Initialised by initialiseVariables()
+       /** @var array */
+       public $mTagHooks = array();
 
-       /**
-        * @var MagicWordArray
-        */
-       var $mVariables;
+       /** @var array */
+       public $mTransparentTagHooks = array();
+
+       /** @var array */
+       public $mFunctionHooks = array();
+
+       /** @var array */
+       protected $mFunctionSynonyms = array( 0 => array(), 1 => array() );
+
+       /** @var array */
+       protected $mFunctionTagHooks = array();
+
+       /** @var array */
+       protected $mStripList = array();
 
        /**
-        * @var MagicWordArray
+        * @var array
+        * @todo Unused?
         */
-       var $mSubstWords;
-       var $mConf, $mPreprocessor, $mExtLinkBracketedRegex, $mUrlProtocols; # Initialised in constructor
+       private $mDefaultStripList = array();
+
+       /** @var array */
+       protected $mVarCache = array();
+
+       /** @var array */
+       protected $mImageParams = array();
+
+       /** @var array */
+       protected $mImageParamsMagicArray = array();
+
+       /** @var int */
+       public $mMarkerIndex = 0;
+
+       /** @var bool */
+       protected $mFirstCall = true;
+
+       # Initialised by initialiseVariables()
+
+       /** @var MagicWordArray */
+       public $mVariables;
+
+       /** @var MagicWordArray */
+       protected $mSubstWords;
+
+       # Initialised in constructor
+
+       /** @var array */
+       protected $mConf;
+
+       /** @var Parser */
+       public $mPreprocessor;
+
+       /** @var string */
+       protected $mExtLinkBracketedRegex;
+
+       /** @var string */
+       protected $mUrlProtocols;
 
        # Cleared with clearState():
-       /**
-        * @var ParserOutput
-        */
-       var $mOutput;
-       var $mAutonumber, $mDTopen;
+
+       /** @var ParserOutput */
+       public $mOutput;
+
+       /** @var int */
+       protected $mAutonumber;
+
+       /** @var bool */
+       protected $mDTopen;
+
+       /** @var StripState */
+       public $mStripState;
 
        /**
-        * @var StripState
+        * @var array
+        * @todo Unused?
         */
-       var $mStripState;
+       private $mIncludeCount;
 
-       var $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
        /**
-        * @var LinkHolderArray
+        * @var bool
+        * @todo Unused?
         */
-       var $mLinkHolders;
+       private $mArgStack;
 
-       var $mLinkID;
-       var $mIncludeSizes, $mPPNodeCount, $mGeneratedPPNodeCount, $mHighestExpansionDepth;
-       var $mDefaultSort;
-       var $mTplExpandCache; # empty-frame expansion cache
-       var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores;
-       var $mExpensiveFunctionCount; # number of expensive parser function calls
-       var $mShowToc, $mForceTocPosition;
+       /** @var string */
+       protected $mLastSection;
 
-       /**
-        * @var User
-        */
-       var $mUser; # User object; only used when doing pre-save transform
+       /** @var bool */
+       protected $mInPre;
+
+       /** @var LinkHolderArray */
+       protected $mLinkHolders;
+
+       /** @var int */
+       protected $mLinkID;
+
+       /** @var array */
+       protected $mIncludeSizes;
+
+       /** @var int */
+       public $mPPNodeCount;
+
+       /** @var int */
+       public $mGeneratedPPNodeCount;
+
+       /** @var int */
+       public $mHighestExpansionDepth;
+
+       /** @var bool|string */
+       protected $mDefaultSort;
+
+       /** @var array Empty-frame expansion cache */
+       protected $mTplExpandCache;
+
+       /** @var array */
+       protected $mTplRedirCache;
+
+       /** @var array */
+       protected $mTplDomCache;
+
+       /** @var array */
+       public $mHeadings;
+
+       /** @var array */
+       protected $mDoubleUnderscores;
+
+       /** @var int Number of expensive parser function calls */
+       protected $mExpensiveFunctionCount;
+
+       /** @var bool */
+       protected $mShowToc;
+
+       /** @var bool */
+       protected $mForceTocPosition;
+
+       /** @var User User object; only used when doing pre-save transform */
+       protected $mUser;
 
        # Temporary
        # These are variables reset at least once per parse regardless of $clearState
 
-       /**
-        * @var ParserOptions
-        */
-       var $mOptions;
+       /** @var ParserOptions */
+       public $mOptions;
 
-       /**
-        * @var Title
-        */
-       var $mTitle;        # Title context, used for self-link rendering and similar things
-       var $mOutputType;   # Output type, one of the OT_xxx constants
-       var $ot;            # Shortcut alias, see setOutputType()
-       var $mRevisionObject; # The revision object of the specified revision ID
-       var $mRevisionId;   # ID to display in {{REVISIONID}} tags
-       var $mRevisionTimestamp; # The timestamp of the specified revision ID
-       var $mRevisionUser; # User to display in {{REVISIONUSER}} tag
-       var $mRevisionSize; # Size to display in {{REVISIONSIZE}} variable
-       var $mRevIdForTs;   # The revision ID which was used to fetch the timestamp
-       var $mInputSize = false; # For {{PAGESIZE}} on current page.
+       /** @var Title Title context, used for self-link rendering and similar things */
+       public $mTitle;
+
+       /** @var array Shortcut alias, see setOutputType() */
+       public $ot;
+
+       /** @var string The timestamp of the specified revision ID */
+       public $mRevisionTimestamp;
+
+       /** @var string */
+       public $mUniqPrefix;
 
        /**
-        * @var string
+        * @var boolean Recursive call protection.
+        * This variable should be treated as if it were private.
         */
-       var $mUniqPrefix;
+       public $mInParse = false;
+
+       /** @var int Output type, one of the OT_xxx constants */
+       protected $mOutputType;
+
+       /** @var Revision The revision object of the specified revision ID */
+       protected $mRevisionObject;
+
+       /** @var int ID to display in {{REVISIONID}} tags */
+       protected $mRevisionId;
+
+       /** @var string User to display in {{REVISIONUSER}} tag */
+       protected $mRevisionUser;
+
+       /** @var int Size to display in {{REVISIONSIZE}} variable */
+       protected $mRevisionSize;
+
+       /** @var bool|int For {{PAGESIZE}} on current page. */
+       protected $mInputSize = false;
 
        /**
-        * @var Array with the language name of each language link (i.e. the
+        * @var array Array with the language name of each language link (i.e. the
         * interwiki prefix) in the key, value arbitrary. Used to avoid sending
         * duplicate language links to the ParserOutput.
         */
-       var $mLangLinkLanguages;
+       protected $mLangLinkLanguages;
 
        /**
-        * Constructor
-        *
-        * @param $conf array
+        * @var int The revision ID which was used to fetch the timestamp
+        * @todo Unused?
+        */
+       private $mRevIdForTs;
+
+       /**
+        * @param array $conf
         */
        public function __construct( $conf = array() ) {
                $this->mConf = $conf;
@@ -254,6 +358,7 @@ class Parser {
         * Allow extensions to clean up when the parser is cloned
         */
        function __clone() {
+               $this->mInParse = false;
                wfRunHooks( 'ParserCloned', array( $this ) );
        }
 
@@ -346,14 +451,16 @@ class Parser {
         * Do not call this function recursively.
         *
         * @param string $text text we want to parse
-        * @param $title Title object
-        * @param $options ParserOptions
-        * @param $linestart boolean
-        * @param $clearState boolean
-        * @param int $revid number to pass in {{REVISIONID}}
-        * @return ParserOutput a ParserOutput
-        */
-       public function parse( $text, Title $title, ParserOptions $options, $linestart = true, $clearState = true, $revid = null ) {
+        * @param Title $title
+        * @param ParserOptions $options
+        * @param bool $linestart
+        * @param bool $clearState
+        * @param int $revid Number to pass in {{REVISIONID}}
+        * @return ParserOutput A ParserOutput
+        */
+       public function parse( $text, Title $title, ParserOptions $options,
+               $linestart = true, $clearState = true, $revid = null
+       ) {
                /**
                 * First pass--just handle <nowiki> sections, pass the rest off
                 * to internalParse() which does all the real work.
@@ -364,6 +471,10 @@ class Parser {
                wfProfileIn( __METHOD__ );
                wfProfileIn( $fname );
 
+               if ( $clearState ) {
+                       $magicScopeVariable = $this->lock();
+               }
+
                $this->startParse( $title, $options, self::OT_HTML, $clearState );
 
                $this->mInputSize = strlen( $text );
@@ -590,8 +701,8 @@ class Parser {
         *
         * If $frame is not provided, then template variables (e.g., {{{1}}}) within $text are not expanded
         *
-        * @param string $text text extension wants to have parsed
-        * @param PPFrame $frame The frame to use for expanding any template variables
+        * @param string $text Text extension wants to have parsed
+        * @param bool|PPFrame $frame The frame to use for expanding any template variables
         *
         * @return string
         */
@@ -607,10 +718,15 @@ class Parser {
        /**
         * Expand templates and variables in the text, producing valid, static wikitext.
         * Also removes comments.
+        * @param string $text
+        * @param Title $title
+        * @param ParserOptions $options
+        * @param int|null $revid
         * @return mixed|string
         */
        function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null ) {
                wfProfileIn( __METHOD__ );
+               $magicScopeVariable = $this->lock();
                $this->startParse( $title, $options, self::OT_PREPROCESS, true );
                if ( $revid !== null ) {
                        $this->mRevisionId = $revid;
@@ -627,8 +743,8 @@ class Parser {
         * Recursive parser entry point that can be called from an extension tag
         * hook.
         *
-        * @param string $text text to be expanded
-        * @param PPFrame $frame The frame to use for expanding any template variables
+        * @param string $text Text to be expanded
+        * @param bool|PPFrame $frame The frame to use for expanding any template variables
         * @return string
         * @since 1.19
         */
@@ -647,17 +763,18 @@ class Parser {
         * transclusion, comments, templates, arguments, tags hooks and parser
         * functions are untouched.
         *
-        * @param $text String
-        * @param $title Title
-        * @param $options ParserOptions
-        * @param $params Array
-        * @return String
+        * @param string $text
+        * @param Title $title
+        * @param ParserOptions $options
+        * @param array $params
+        * @return string
         */
        public function getPreloadText( $text, Title $title, ParserOptions $options, $params = array() ) {
                $msg = new RawMessage( $text );
                $text = $msg->params( $params )->plain();
 
                # Parser (re)initialisation
+               $magicScopeVariable = $this->lock();
                $this->startParse( $title, $options, self::OT_PLAIN, true );
 
                $flags = PPFrame::NO_ARGS | PPFrame::NO_TEMPLATES;
@@ -689,7 +806,7 @@ class Parser {
        /**
         * Accessor for mUniqPrefix.
         *
-        * @return String
+        * @return string
         */
        public function uniqPrefix() {
                if ( !isset( $this->mUniqPrefix ) ) {
@@ -707,7 +824,7 @@ class Parser {
        /**
         * Set the context title
         *
-        * @param $t Title
+        * @param Title $t
         */
        function setTitle( $t ) {
                if ( !$t ) {
@@ -726,7 +843,7 @@ class Parser {
        /**
         * Accessor for the Title object
         *
-        * @return Title object
+        * @return Title
         */
        function getTitle() {
                return $this->mTitle;
@@ -735,8 +852,8 @@ class Parser {
        /**
         * Accessor/mutator for the Title object
         *
-        * @param $x Title object or null to just get the current one
-        * @return Title object
+        * @param Title $x Title object or null to just get the current one
+        * @return Title
         */
        function Title( $x = null ) {
                return wfSetVar( $this->mTitle, $x );
@@ -745,7 +862,7 @@ class Parser {
        /**
         * Set the output type
         *
-        * @param int $ot new value
+        * @param int $ot New value
         */
        function setOutputType( $ot ) {
                $this->mOutputType = $ot;
@@ -762,7 +879,7 @@ class Parser {
         * Accessor/mutator for the output type
         *
         * @param int|null $x New value or null to just get the current one
-        * @return Integer
+        * @return int
         */
        function OutputType( $x = null ) {
                return wfSetVar( $this->mOutputType, $x );
@@ -771,7 +888,7 @@ class Parser {
        /**
         * Get the ParserOutput object
         *
-        * @return ParserOutput object
+        * @return ParserOutput
         */
        function getOutput() {
                return $this->mOutput;
@@ -789,7 +906,7 @@ class Parser {
        /**
         * Accessor/mutator for the ParserOptions object
         *
-        * @param $x ParserOptions New value or null to just get the current one
+        * @param ParserOptions $x New value or null to just get the current one
         * @return ParserOptions Current ParserOptions object
         */
        function Options( $x = null ) {
@@ -804,7 +921,7 @@ class Parser {
        }
 
        /**
-        * @param $id int
+        * @param int $id
         */
        function setLinkID( $id ) {
                $this->mLinkID = $id;
@@ -843,6 +960,7 @@ class Parser {
 
        /**
         * Get the language object for language conversion
+        * @return Language|null
         */
        function getConverterLanguage() {
                return $this->getTargetLanguage();
@@ -852,7 +970,7 @@ class Parser {
         * Get a User object either from $this->mUser, if set, or from the
         * ParserOptions object otherwise
         *
-        * @return User object
+        * @return User
         */
        function getUser() {
                if ( !is_null( $this->mUser ) ) {
@@ -864,7 +982,7 @@ class Parser {
        /**
         * Get a preprocessor object
         *
-        * @return Preprocessor instance
+        * @return Preprocessor
         */
        function getPreprocessor() {
                if ( !isset( $this->mPreprocessor ) ) {
@@ -970,7 +1088,7 @@ class Parser {
         * Returns the unique tag which must be inserted into the stripped text
         * The tag will be replaced with the original text in unstrip()
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string
         */
@@ -985,6 +1103,7 @@ class Parser {
         * parse the wiki syntax used to render tables
         *
         * @private
+        * @param string $text
         * @return string
         */
        function doTableStuff( $text ) {
@@ -1072,7 +1191,10 @@ class Parser {
                                array_push( $tr_history, false );
                                array_push( $td_history, false );
                                array_push( $last_tag_history, '' );
-                       } elseif ( $first_character === '|' || $first_character === '!' || substr( $line, 0, 2 ) === '|+' ) {
+                       } elseif ( $first_character === '|'
+                               || $first_character === '!'
+                               || substr( $line, 0, 2 ) === '|+'
+                       ) {
                                # This might be cell elements, td, th or captions
                                if ( substr( $line, 0, 2 ) === '|+' ) {
                                        $first_character = '+';
@@ -1183,9 +1305,9 @@ class Parser {
         *
         * @private
         *
-        * @param $text string
-        * @param $isMain bool
-        * @param $frame bool
+        * @param string $text
+        * @param bool $isMain
+        * @param bool $frame
         *
         * @return string
         */
@@ -1217,7 +1339,12 @@ class Parser {
                }
 
                wfRunHooks( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
-               $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ), false, array_keys( $this->mTransparentTagHooks ) );
+               $text = Sanitizer::removeHTMLtags(
+                       $text,
+                       array( &$this, 'attributeStripCallback' ),
+                       false,
+                       array_keys( $this->mTransparentTagHooks )
+               );
                wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
 
                # Tables need to come after variable replacement for things to work
@@ -1253,7 +1380,7 @@ class Parser {
         * DML
         * @private
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string
         */
@@ -1279,7 +1406,7 @@ class Parser {
 
        /**
         * @throws MWException
-        * @param $m array
+        * @param array $m
         * @return HTML|string
         */
        function magicLinkCallback( $m ) {
@@ -1330,7 +1457,7 @@ class Parser {
        /**
         * Make a free external link, given a user-supplied URL
         *
-        * @param $url string
+        * @param string $url
         *
         * @return string HTML
         * @private
@@ -1386,7 +1513,7 @@ class Parser {
         *
         * @private
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string
         */
@@ -1404,7 +1531,7 @@ class Parser {
         * Replace single quotes with HTML markup
         * @private
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string the altered text
         */
@@ -1423,7 +1550,7 @@ class Parser {
        /**
         * Helper function for doAllQuotes()
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string
         */
@@ -1612,7 +1739,7 @@ class Parser {
         *
         * @private
         *
-        * @param $text string
+        * @param string $text
         *
         * @throws MWException
         * @return string
@@ -1623,7 +1750,8 @@ class Parser {
                $bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
                if ( $bits === false ) {
                        wfProfileOut( __METHOD__ );
-                       throw new MWException( "PCRE needs to be compiled with --enable-unicode-properties in order for MediaWiki to function" );
+                       throw new MWException( "PCRE needs to be compiled with "
+                               . "--enable-unicode-properties in order for MediaWiki to function" );
                }
                $s = array_shift( $bits );
 
@@ -1693,10 +1821,10 @@ class Parser {
         * Get the rel attribute for a particular external link.
         *
         * @since 1.21
-        * @param string|bool $url optional URL, to extract the domain from for rel =>
+        * @param string|bool $url Optional URL, to extract the domain from for rel =>
         *   nofollow if appropriate
-        * @param $title Title optional Title, for wgNoFollowNsExceptions lookups
-        * @return string|null rel attribute for $url
+        * @param Title $title Optional Title, for wgNoFollowNsExceptions lookups
+        * @return string|null Rel attribute for $url
         */
        public static function getExternalLinkRel( $url = false, $title = null ) {
                global $wgNoFollowLinks, $wgNoFollowNsExceptions, $wgNoFollowDomainExceptions;
@@ -1715,9 +1843,9 @@ class Parser {
         * (depending on configuration, namespace, and the URL's domain) and/or a
         * target attribute (depending on configuration).
         *
-        * @param string|bool $url optional URL, to extract the domain from for rel =>
+        * @param string|bool $url Optional URL, to extract the domain from for rel =>
         *   nofollow if appropriate
-        * @return Array associative array of HTML attributes
+        * @return array Associative array of HTML attributes
         */
        function getExternalLinkAttribs( $url = false ) {
                $attribs = array();
@@ -1732,8 +1860,8 @@ class Parser {
        /**
         * Replace unusual URL escape codes with their equivalent characters
         *
-        * @param $url String
-        * @return String
+        * @param string $url
+        * @return string
         *
         * @todo This can merge genuinely required bits in the path or query string,
         *       breaking legit URLs. A proper fix would treat the various parts of
@@ -1749,7 +1877,7 @@ class Parser {
         * Callback function used in replaceUnusualEscapes().
         * Replaces unusual URL escape codes with their equivalent character
         *
-        * @param $matches array
+        * @param array $matches
         *
         * @return string
         */
@@ -1771,7 +1899,7 @@ class Parser {
         * option, through the exception, or through the on-wiki whitelist
         * @private
         *
-        * $param $url string
+        * $param string $url
         *
         * @return string
         */
@@ -1793,16 +1921,23 @@ class Parser {
                } else {
                        $imagematch = false;
                }
+
                if ( $this->mOptions->getAllowExternalImages()
-                       || ( $imagesexception && $imagematch ) ) {
+                       || ( $imagesexception && $imagematch )
+               ) {
                        if ( preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
                                # Image found
                                $text = Linker::makeExternalImage( $url );
                        }
                }
                if ( !$text && $this->mOptions->getEnableImageWhitelist()
-                       && preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
-                       $whitelist = explode( "\n", wfMessage( 'external_image_whitelist' )->inContentLanguage()->text() );
+                       && preg_match( self::EXT_IMAGE_REGEX, $url )
+               ) {
+                       $whitelist = explode(
+                               "\n",
+                               wfMessage( 'external_image_whitelist' )->inContentLanguage()->text()
+                       );
+
                        foreach ( $whitelist as $entry ) {
                                # Sanitize the regex fragment, make it case-insensitive, ignore blank entries/comments
                                if ( strpos( $entry, '#' ) === 0 || $entry === '' ) {
@@ -1834,7 +1969,7 @@ class Parser {
 
        /**
         * Process [[ ]] wikilinks (RIL)
-        * @param $s
+        * @param string $s
         * @throws MWException
         * @return LinkHolderArray
         *
@@ -1895,8 +2030,11 @@ class Parser {
                $useSubpages = $this->areSubpagesAllowed();
                wfProfileOut( __METHOD__ . '-setup' );
 
+               // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
                # Loop for each link
                for ( ; $line !== false && $line !== null; $a->next(), $line = $a->current() ) {
+                       // @codingStandardsIgnoreStart
+
                        # Check for excessive memory usage
                        if ( $holders->isBig() ) {
                                # Too big
@@ -1947,7 +2085,8 @@ class Parser {
                                        $m[1] = str_replace( array( '<', '>' ), array( '&lt;', '&gt;' ), rawurldecode( $m[1] ) );
                                }
                                $trail = $m[3];
-                       } elseif ( preg_match( $e1_img, $line, $m ) ) { # Invalid, but might be an image with a link in its caption
+                       } elseif ( preg_match( $e1_img, $line, $m ) ) {
+                               # Invalid, but might be an image with a link in its caption
                                $might_be_img = true;
                                $text = $m[2];
                                if ( strpos( $m[1], '%' ) !== false ) {
@@ -2057,7 +2196,9 @@ class Parser {
                        if ( $noforce ) {
                                # Interwikis
                                wfProfileIn( __METHOD__ . "-interwiki" );
-                               if ( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && Language::fetchLanguageName( $iw, null, 'mw' ) ) {
+                               if ( $iw && $this->mOptions->getInterwikiMagic()
+                                       && $nottalk && Language::fetchLanguageName( $iw, null, 'mw' )
+                               ) {
                                        // XXX: the above check prevents links to sites with identifiers that are not language codes
 
                                        # Bug 24502: filter duplicates
@@ -2214,7 +2355,7 @@ class Parser {
 
        /**
         * Return true if subpage links should be expanded on this page.
-        * @return Boolean
+        * @return bool
         */
        function areSubpagesAllowed() {
                # Some namespaces don't allow subpages
@@ -2254,8 +2395,8 @@ class Parser {
         * of both arguments, starting at the beginning of both.
         * @private
         *
-        * @param $st1 string
-        * @param $st2 string
+        * @param string $st1
+        * @param string $st2
         *
         * @return int
         */
@@ -2279,7 +2420,7 @@ class Parser {
         * element appropriate to the prefix character passed into them.
         * @private
         *
-        * @param $char string
+        * @param string $char
         *
         * @return string
         */
@@ -2304,7 +2445,7 @@ class Parser {
 
        /**
         * TODO: document
-        * @param $char String
+        * @param string $char
         * @private
         *
         * @return string
@@ -2329,8 +2470,8 @@ class Parser {
        }
 
        /**
-        * TODO: document
-        * @param $char String
+        * @todo Document
+        * @param string $char
         * @private
         *
         * @return string
@@ -2469,13 +2610,22 @@ class Parser {
                                wfProfileIn( __METHOD__ . "-paragraph" );
                                # No prefix (not in list)--go to paragraph mode
                                # XXX: use a stack for nestable elements like span, table and div
-                               $openmatch = preg_match( '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS', $t );
+                               $openmatch = preg_match(
+                                       '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
+                                               . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS',
+                                       $t
+                               );
                                $closematch = preg_match(
-                                       '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|' .
-                                       '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|' . $this->mUniqPrefix . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS', $t );
+                                       '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
+                                               . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
+                                               . $this->mUniqPrefix
+                                               . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
+                                       $t
+                               );
+
                                if ( $openmatch or $closematch ) {
                                        $paragraphStack = false;
-                                       # TODO bug 5718: paragraph closed
+                                       # @todo bug 5718: paragraph closed
                                        $output .= $this->closeParagraph();
                                        if ( $preOpenMatch and !$preCloseMatch ) {
                                                $this->mInPre = true;
@@ -2487,7 +2637,10 @@ class Parser {
                                        }
                                        $inBlockElem = !$closematch;
                                } elseif ( !$inBlockElem && !$this->mInPre ) {
-                                       if ( ' ' == substr( $t, 0, 1 ) and ( $this->mLastSection === 'pre' || trim( $t ) != '' ) and !$inBlockquote ) {
+                                       if ( ' ' == substr( $t, 0, 1 )
+                                               && ( $this->mLastSection === 'pre' || trim( $t ) != '' )
+                                               && !$inBlockquote
+                                       ) {
                                                # pre
                                                if ( $this->mLastSection !== 'pre' ) {
                                                        $paragraphStack = false;
@@ -2550,11 +2703,11 @@ class Parser {
         * Split up a string on ':', ignoring any occurrences inside tags
         * to prevent illegal overlapping.
         *
-        * @param string $str the string to split
-        * @param &$before String set to everything before the ':'
-        * @param &$after String set to everything after the ':'
+        * @param string $str The string to split
+        * @param string &$before Set to everything before the ':'
+        * @param string &$after Set to everything after the ':'
         * @throws MWException
-        * @return String the position of the ':', or false if none found
+        * @return string The position of the ':', or false if none found
         */
        function findColonNoLinks( $str, &$before, &$after ) {
                wfProfileIn( __METHOD__ );
@@ -2718,14 +2871,14 @@ class Parser {
         *
         * @private
         *
-        * @param $index integer
-        * @param bool|\PPFrame $frame
+        * @param int $index
+        * @param bool|PPFrame $frame
         *
         * @throws MWException
         * @return string
         */
        function getVariableValue( $index, $frame = false ) {
-               global $wgContLang, $wgSitename, $wgServer;
+               global $wgContLang, $wgSitename, $wgServer, $wgServerName;
                global $wgArticlePath, $wgScriptPath, $wgStylePath;
 
                if ( is_null( $this->mTitle ) ) {
@@ -2817,13 +2970,21 @@ class Parser {
                                $value = wfEscapeWikiText( $this->mTitle->getRootText() );
                                break;
                        case 'rootpagenamee':
-                               $value = wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getRootText() ) ) );
+                               $value = wfEscapeWikiText( wfUrlEncode( str_replace(
+                                       ' ',
+                                       '_',
+                                       $this->mTitle->getRootText()
+                               ) ) );
                                break;
                        case 'basepagename':
                                $value = wfEscapeWikiText( $this->mTitle->getBaseText() );
                                break;
                        case 'basepagenamee':
-                               $value = wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getBaseText() ) ) );
+                               $value = wfEscapeWikiText( wfUrlEncode( str_replace(
+                                       ' ',
+                                       '_',
+                                       $this->mTitle->getBaseText()
+                               ) ) );
                                break;
                        case 'talkpagename':
                                if ( $this->mTitle->canTalk() ) {
@@ -2934,7 +3095,9 @@ class Parser {
                                $value = $this->mTitle->getNamespace();
                                break;
                        case 'talkspace':
-                               $value = $this->mTitle->canTalk() ? str_replace( '_', ' ', $this->mTitle->getTalkNsText() ) : '';
+                               $value = $this->mTitle->canTalk()
+                                       ? str_replace( '_', ' ', $this->mTitle->getTalkNsText() )
+                                       : '';
                                break;
                        case 'talkspacee':
                                $value = $this->mTitle->canTalk() ? wfUrlencode( $this->mTitle->getTalkNsText() ) : '';
@@ -2966,13 +3129,19 @@ class Parser {
                                $value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'w' ) );
                                break;
                        case 'localdayname':
-                               $value = $pageLang->getWeekdayName( (int)MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1 );
+                               $value = $pageLang->getWeekdayName(
+                                       (int)MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1
+                               );
                                break;
                        case 'localyear':
                                $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'Y' ), true );
                                break;
                        case 'localtime':
-                               $value = $pageLang->time( MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ), false, false );
+                               $value = $pageLang->time(
+                                       MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ),
+                                       false,
+                                       false
+                               );
                                break;
                        case 'localhour':
                                $value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'H' ), true );
@@ -3026,8 +3195,7 @@ class Parser {
                        case 'server':
                                return $wgServer;
                        case 'servername':
-                               $serverParts = wfParseUrl( $wgServer );
-                               return $serverParts && isset( $serverParts['host'] ) ? $serverParts['host'] : $wgServer;
+                               return $wgServerName;
                        case 'scriptpath':
                                return $wgScriptPath;
                        case 'stylepath':
@@ -3042,7 +3210,11 @@ class Parser {
                                break;
                        default:
                                $ret = null;
-                               wfRunHooks( 'ParserGetVariableValueSwitch', array( &$this, &$this->mVarCache, &$index, &$ret, &$frame ) );
+                               wfRunHooks(
+                                       'ParserGetVariableValueSwitch',
+                                       array( &$this, &$this->mVarCache, &$index, &$ret, &$frame )
+                               );
+
                                return $ret;
                }
 
@@ -3098,7 +3270,7 @@ class Parser {
        /**
         * Return a three-element array: leading whitespace, string contents, trailing whitespace
         *
-        * @param $s string
+        * @param string $s
         *
         * @return array
         */
@@ -3125,11 +3297,11 @@ class Parser {
         *  self::OT_PREPROCESS: templates but not extension tags
         *  self::OT_HTML: all templates and extension tags
         *
-        * @param string $text the text to transform
-        * @param $frame PPFrame Object describing the arguments passed to the template.
+        * @param string $text The text to transform
+        * @param PPFrame $frame Object describing the arguments passed to the template.
         *        Arguments may also be provided as an associative array, as was the usual case before MW1.12.
         *        Providing arguments this way may be useful for extensions wishing to perform variable replacement explicitly.
-        * @param $argsOnly Boolean only do argument (triple-brace) expansion, not double-brace expansion
+        * @param bool $argsOnly Only do argument (triple-brace) expansion, not double-brace expansion
         * @private
         *
         * @return string
@@ -3144,7 +3316,8 @@ class Parser {
                if ( $frame === false ) {
                        $frame = $this->getPreprocessor()->newFrame();
                } elseif ( !( $frame instanceof PPFrame ) ) {
-                       wfDebug( __METHOD__ . " called using plain parameters instead of a PPFrame instance. Creating custom frame.\n" );
+                       wfDebug( __METHOD__ . " called using plain parameters instead of "
+                               . "a PPFrame instance. Creating custom frame.\n" );
                        $frame = $this->getPreprocessor()->newCustomFrame( $frame );
                }
 
@@ -3159,7 +3332,7 @@ class Parser {
        /**
         * Clean up argument array - refactored in 1.9 so parserfunctions can use it, too.
         *
-        * @param $args array
+        * @param array $args
         *
         * @return array
         */
@@ -3189,7 +3362,7 @@ class Parser {
         * Warn the user when a parser limitation is reached
         * Will warn at most once the user per limitation type
         *
-        * @param string $limitationType should be one of:
+        * @param string $limitationType Should be one of:
         *   'expensive-parserfunction' (corresponding messages:
         *       'expensive-parserfunction-warning',
         *       'expensive-parserfunction-category')
@@ -3205,8 +3378,8 @@ class Parser {
         *   'expansion-depth-exceeded' (corresponding messages:
         *       'expansion-depth-exceeded-warning',
         *       'expansion-depth-exceeded-category')
-        * @param int|null $current Current value
-        * @param int|null $max Maximum allowed, when an explicit limit has been
+        * @param string|int|null $current Current value
+        * @param string|int|null $max Maximum allowed, when an explicit limit has been
         *       exceeded, provide the values (optional)
         */
        function limitationWarn( $limitationType, $current = '', $max = '' ) {
@@ -3222,11 +3395,11 @@ class Parser {
         * replacing any variables or templates within the template.
         *
         * @param array $piece The parts of the template
-        *  $piece['title']: the title, i.e. the part before the |
-        *  $piece['parts']: the parameter array
-        *  $piece['lineStart']: whether the brace was at the start of a line
+        *   $piece['title']: the title, i.e. the part before the |
+        *   $piece['parts']: the parameter array
+        *   $piece['lineStart']: whether the brace was at the start of a line
         * @param PPFrame $frame The current frame, contains template arguments
-        * @throws MWException
+        * @throws Exception
         * @return string The text of the template
         * @private
         */
@@ -3234,13 +3407,20 @@ class Parser {
                wfProfileIn( __METHOD__ );
                wfProfileIn( __METHOD__ . '-setup' );
 
-               # Flags
-               $found = false;             # $text has been filled
-               $nowiki = false;            # wiki markup in $text should be escaped
-               $isHTML = false;            # $text is HTML, armour it against wikitext transformation
-               $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered
-               $isChildObj = false;        # $text is a DOM node needing expansion in a child frame
-               $isLocalObj = false;        # $text is a DOM node needing expansion in the current frame
+               // Flags
+
+               // $text has been filled
+               $found = false;
+               // wiki markup in $text should be escaped
+               $nowiki = false;
+               // $text is HTML, armour it against wikitext transformation
+               $isHTML = false;
+               // Force interwiki transclusion to be done in raw mode not rendered
+               $forceRawInterwiki = false;
+               // $text is a DOM node needing expansion in a child frame
+               $isChildObj = false;
+               // $text is a DOM node needing expansion in the current frame
+               $isLocalObj = false;
 
                # Title object, where $text came from
                $title = false;
@@ -3255,7 +3435,8 @@ class Parser {
                $originalTitle = $part1;
 
                # $args is a list of argument nodes, starting from index 0, not including $part1
-               # @todo FIXME: If piece['parts'] is null then the call to getLength() below won't work b/c this $args isn't an object
+               # @todo FIXME: If piece['parts'] is null then the call to getLength()
+               # below won't work b/c this $args isn't an object
                $args = ( null == $piece['parts'] ) ? array() : $piece['parts'];
                wfProfileOut( __METHOD__ . '-setup' );
 
@@ -3395,7 +3576,8 @@ class Parser {
                                        // "uselang" will have no effect since the Language object
                                        // is forced to the one defined in ParserOptions.
                                        $pageArgs = array();
-                                       for ( $i = 0; $i < $args->getLength(); $i++ ) {
+                                       $argsLength = $args->getLength();
+                                       for ( $i = 0; $i < $argsLength; $i++ ) {
                                                $bits = $args->item( $i )->splitArg();
                                                if ( strval( $bits['index'] ) === '' ) {
                                                        $name = trim( $frame->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
@@ -3528,7 +3710,8 @@ class Parser {
                                preg_replace( '/^:/', '', $originalTitle );
                                $text = "[[:$originalTitle]]";
                        }
-                       $text .= $this->insertStripItem( '<!-- WARNING: template omitted, post-expand include size too large -->' );
+                       $text .= $this->insertStripItem( '<!-- WARNING: template omitted, '
+                               . 'post-expand include size too large -->' );
                        $this->limitationWarn( 'post-expand-template-inclusion' );
                }
 
@@ -3555,9 +3738,10 @@ class Parser {
         *  nowiki: bool, wiki markup in $text should be escaped
         *
         * @since 1.21
-        * @param $frame PPFrame The current frame, contains template arguments
-        * @param $function string Function name
-        * @param $args array Arguments to the function
+        * @param PPFrame $frame The current frame, contains template arguments
+        * @param string $function Function name
+        * @param array $args Arguments to the function
+        * @throws MWException
         * @return array
         */
        public function callParserFunction( $frame, $function, array $args = array() ) {
@@ -3660,7 +3844,7 @@ class Parser {
         * Get the semi-parsed DOM representation of a template with a given title,
         * and its redirect destination title. Cached.
         *
-        * @param $title Title
+        * @param Title $title
         *
         * @return array
         */
@@ -3699,10 +3883,11 @@ class Parser {
        /**
         * Fetch the unparsed text of a template and register a reference to it.
         * @param Title $title
-        * @return Array ( string or false, Title )
+        * @return array ( string or false, Title )
         */
        function fetchTemplateAndTitle( $title ) {
-               $templateCb = $this->mOptions->getTemplateCallback(); # Defaults to Parser::statelessFetchTemplate()
+               // Defaults to Parser::statelessFetchTemplate()
+               $templateCb = $this->mOptions->getTemplateCallback();
                $stuff = call_user_func( $templateCb, $title, $this );
                $text = $stuff['text'];
                $finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
@@ -3722,7 +3907,7 @@ class Parser {
        /**
         * Fetch the unparsed text of a template and register a reference to it.
         * @param Title $title
-        * @return mixed string or false
+        * @return string|bool
         */
        function fetchTemplate( $title ) {
                $rv = $this->fetchTemplateAndTitle( $title );
@@ -3734,7 +3919,7 @@ class Parser {
         * Can be overridden via ParserOptions::setTemplateCallback().
         *
         * @param Title $title
-        * @param Parser $parser
+        * @param bool|Parser $parser
         *
         * @return array
         */
@@ -3832,7 +4017,7 @@ class Parser {
         * If 'broken' is a key in $options then the file will appear as a broken thumbnail.
         * @param Title $title
         * @param array $options Array of options to RepoGroup::findFile
-        * @return Array ( File or false, Title of file )
+        * @return array ( File or false, Title of file )
         */
        function fetchFileAndTitle( $title, $options = array() ) {
                $file = $this->fetchFileNoRegister( $title, $options );
@@ -3857,7 +4042,7 @@ class Parser {
         *
         * @param Title $title
         * @param array $options Array of options to RepoGroup::findFile
-        * @return File or false
+        * @return File|bool
         */
        protected function fetchFileNoRegister( $title, $options = array() ) {
                if ( isset( $options['broken'] ) ) {
@@ -3873,8 +4058,8 @@ class Parser {
        /**
         * Transclude an interwiki link.
         *
-        * @param $title Title
-        * @param $action
+        * @param Title $title
+        * @param string $action
         *
         * @return string
         */
@@ -3894,8 +4079,8 @@ class Parser {
        }
 
        /**
-        * @param $url string
-        * @return Mixed|String
+        * @param string $url
+        * @return mixed|string
         */
        function fetchScaryTemplateMaybeFromCache( $url ) {
                global $wgTranscludeCacheExpiry;
@@ -3911,8 +4096,10 @@ class Parser {
                $status = $req->execute(); // Status object
                if ( $status->isOK() ) {
                        $text = $req->getContent();
-               } elseif ( $req->getStatus() != 200 ) { // Though we failed to fetch the content, this status is useless.
-                       return wfMessage( 'scarytranscludefailed-httpstatus', $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text();
+               } elseif ( $req->getStatus() != 200 ) {
+                       // Though we failed to fetch the content, this status is useless.
+                       return wfMessage( 'scarytranscludefailed-httpstatus' )
+                               ->params( $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text();
                } else {
                        return wfMessage( 'scarytranscludefailed', $url )->inContentLanguage()->text();
                }
@@ -3930,8 +4117,8 @@ class Parser {
         * Triple brace replacement -- used for template arguments
         * @private
         *
-        * @param $piece array
-        * @param $frame PPFrame
+        * @param array $piece
+        * @param PPFrame $frame
         *
         * @return array
         */
@@ -3985,7 +4172,7 @@ class Parser {
         *     attributes Optional associative array of parsed attributes
         *     inner      Contents of extension element
         *     noClose    Original text did not have a close tag
-        * @param $frame PPFrame
+        * @param PPFrame $frame
         *
         * @throws MWException
         * @return string
@@ -3994,7 +4181,8 @@ class Parser {
                $name = $frame->expand( $params['name'] );
                $attrText = !isset( $params['attr'] ) ? null : $frame->expand( $params['attr'] );
                $content = !isset( $params['inner'] ) ? null : $frame->expand( $params['inner'] );
-               $marker = "{$this->mUniqPrefix}-$name-" . sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
+               $marker = "{$this->mUniqPrefix}-$name-"
+                       . sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
 
                $isFunctionTag = isset( $this->mFunctionTagHooks[strtolower( $name )] ) &&
                        ( $this->ot['html'] || $this->ot['pre'] );
@@ -4071,7 +4259,7 @@ class Parser {
         *
         * @param string $type The type of expansion
         * @param int $size The size of the text
-        * @return bool false if this inclusion would take it over the maximum, true otherwise
+        * @return bool False if this inclusion would take it over the maximum, true otherwise
         */
        function incrementIncludeSize( $type, $size ) {
                if ( $this->mIncludeSizes[$type] + $size > $this->mOptions->getMaxIncludeSize() ) {
@@ -4085,7 +4273,7 @@ class Parser {
        /**
         * Increment the expensive function count
         *
-        * @return bool false if the limit has been exceeded
+        * @return bool False if the limit has been exceeded
         */
        function incrementExpensiveFunctionCount() {
                $this->mExpensiveFunctionCount++;
@@ -4096,7 +4284,7 @@ class Parser {
         * Strip double-underscore items like __NOGALLERY__ and __NOTOC__
         * Fills $this->mDoubleUnderscores, returns the modified text
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string
         */
@@ -4126,7 +4314,9 @@ class Parser {
                if ( isset( $this->mDoubleUnderscores['notoc'] ) && !$this->mForceTocPosition ) {
                        $this->mShowToc = false;
                }
-               if ( isset( $this->mDoubleUnderscores['hiddencat'] ) && $this->mTitle->getNamespace() == NS_CATEGORY ) {
+               if ( isset( $this->mDoubleUnderscores['hiddencat'] )
+                       && $this->mTitle->getNamespace() == NS_CATEGORY
+               ) {
                        $this->addTrackingCategory( 'hidden-category-category' );
                }
                # (bug 8068) Allow control over whether robots index a page.
@@ -4198,9 +4388,9 @@ class Parser {
         * It loops through all headlines, collects the necessary data, then splits up the
         * string and re-inserts the newly formatted headlines.
         *
-        * @param $text String
-        * @param string $origText original, untouched wikitext
-        * @param $isMain Boolean
+        * @param string $text
+        * @param string $origText Original, untouched wikitext
+        * @param bool $isMain
         * @return mixed|string
         * @private
         */
@@ -4221,7 +4411,11 @@ class Parser {
                # Get all headlines for numbering them and adding funky stuff like [edit]
                # links - this is for later, but we need the number of headlines right now
                $matches = array();
-               $numMatches = preg_match_all( '/<H(?P<level>[1-6])(?P<attrib>.*?' . '>)\s*(?P<header>[\s\S]*?)\s*<\/H[1-6] *>/i', $text, $matches );
+               $numMatches = preg_match_all(
+                       '/<H(?P<level>[1-6])(?P<attrib>.*?' . '>)\s*(?P<header>[\s\S]*?)\s*<\/H[1-6] *>/i',
+                       $text,
+                       $matches
+               );
 
                # if there are fewer than 4 headlines in the article, do not show TOC
                # unless it's been explicitly enabled.
@@ -4370,7 +4564,10 @@ class Parser {
                        # We strip any parameter from accepted tags (second regex), except dir="rtl|ltr" from <span>,
                        # to allow setting directionality in toc items.
                        $tocline = preg_replace(
-                               array( '#<(?!/?(span|sup|sub|i|b)(?: [^>]*)?>).*?' . '>#', '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|i|b))(?: .*?)?' . '>#' ),
+                               array(
+                                       '#<(?!/?(span|sup|sub|i|b)(?: [^>]*)?>).*?' . '>#',
+                                       '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|i|b))(?: .*?)?' . '>#'
+                               ),
                                array( '', '<$1>' ),
                                $safeHeadline
                        );
@@ -4434,7 +4631,11 @@ class Parser {
                        # Don't number the heading if it is the only one (looks silly)
                        if ( count( $matches[3] ) > 1 && $this->mOptions->getNumberHeadings() ) {
                                # the two are different if the line contains a link
-                               $headline = Html::element( 'span', array( 'class' => 'mw-headline-number' ), $numbering ) . ' ' . $headline;
+                               $headline = Html::element(
+                                       'span',
+                                       array( 'class' => 'mw-headline-number' ),
+                                       $numbering
+                               ) . ' ' . $headline;
                        }
 
                        # Create the anchor for linking from the TOC to the section
@@ -4484,14 +4685,22 @@ class Parser {
                                        # that sections inside <includeonly> should be counted.
                                        $editlinkArgs = array( $titleText, "T-$sectionIndex"/*, null */ );
                                } else {
-                                       $editlinkArgs = array( $this->mTitle->getPrefixedText(), $sectionIndex, $headlineHint );
+                                       $editlinkArgs = array(
+                                               $this->mTitle->getPrefixedText(),
+                                               $sectionIndex,
+                                               $headlineHint
+                                       );
                                }
-                               // We use a bit of pesudo-xml for editsection markers. The language converter is run later on
-                               // Using a UNIQ style marker leads to the converter screwing up the tokens when it converts stuff
-                               // And trying to insert strip tags fails too. At this point all real inputted tags have already been escaped
-                               // so we don't have to worry about a user trying to input one of these markers directly.
-                               // We use a page and section attribute to stop the language converter from converting these important bits
-                               // of data, but put the headline hint inside a content block because the language converter is supposed to
+                               // We use a bit of pesudo-xml for editsection markers. The
+                               // language converter is run later on. Using a UNIQ style marker
+                               // leads to the converter screwing up the tokens when it
+                               // converts stuff. And trying to insert strip tags fails too. At
+                               // this point all real inputted tags have already been escaped,
+                               // so we don't have to worry about a user trying to input one of
+                               // these markers directly. We use a page and section attribute
+                               // to stop the language converter from converting these
+                               // important bits of data, but put the headline hint inside a
+                               // content block because the language converter is supposed to
                                // be able to convert that piece of data.
                                $editlink = '<mw:editsection page="' . htmlspecialchars( $editlinkArgs[0] );
                                $editlink .= '" section="' . htmlspecialchars( $editlinkArgs[1] ) . '"';
@@ -4586,7 +4795,12 @@ class Parser {
         * @param bool $clearState Whether to clear the parser state first
         * @return string The altered wiki markup
         */
-       public function preSaveTransform( $text, Title $title, User $user, ParserOptions $options, $clearState = true ) {
+       public function preSaveTransform( $text, Title $title, User $user,
+               ParserOptions $options, $clearState = true
+       ) {
+               if ( $clearState ) {
+                       $magicScopeVariable = $this->lock();
+               }
                $this->startParse( $title, $options, self::OT_WIKI, $clearState );
                $this->setUser( $user );
 
@@ -4607,8 +4821,8 @@ class Parser {
        /**
         * Pre-save transform helper function
         *
-        * @param $text string
-        * @param $user User
+        * @param string $text
+        * @param User $user
         *
         * @return string
         */
@@ -4655,10 +4869,14 @@ class Parser {
                $tc = '[' . Title::legalChars() . ']';
                $nc = '[ _0-9A-Za-z\x80-\xff-]'; # Namespaces can use non-ascii!
 
-               $p1 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\))\\|]]/";                   # [[ns:page (context)|]]
-               $p4 = "/\[\[(:?$nc+:|:|)($tc+?)( ?($tc+))\\|]]/";                           # [[ns:page(context)|]] (double-width brackets, added in r40257)
-               $p3 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\)|)((?:, |,)$tc+|)\\|]]/";         # [[ns:page (context), context|]] (using either single or double-width comma)
-               $p2 = "/\[\[\\|($tc+)]]/";                                              # [[|page]] (reverse pipe trick: add context from page title)
+               // [[ns:page (context)|]]
+               $p1 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\))\\|]]/";
+               // [[ns:page(context)|]] (double-width brackets, added in r40257)
+               $p4 = "/\[\[(:?$nc+:|:|)($tc+?)( ?($tc+))\\|]]/";
+               // [[ns:page (context), context|]] (using either single or double-width comma)
+               $p3 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\)|)((?:, |,)$tc+|)\\|]]/";
+               // [[|page]] (reverse pipe trick: add context from page title)
+               $p2 = "/\[\[\\|($tc+)]]/";
 
                # try $p1 first, to turn "[[A, B (C)|]]" into "[[A, B (C)|A, B]]"
                $text = preg_replace( $p1, '[[\\1\\2\\3|\\2]]', $text );
@@ -4690,10 +4908,10 @@ class Parser {
         * Do not reuse this parser instance after calling getUserSig(),
         * as it may have changed if it's the $wgParser.
         *
-        * @param $user User
-        * @param string|bool $nickname nickname to use or false to use user's default nickname
-        * @param $fancySig Boolean|null whether the nicknname is the complete signature
-        *                  or null to use default value
+        * @param User $user
+        * @param string|bool $nickname Nickname to use or false to use user's default nickname
+        * @param bool|null $fancySig whether the nicknname is the complete signature
+        *    or null to use default value
         * @return string
         */
        function getUserSig( &$user, $nickname = false, $fancySig = null ) {
@@ -4735,14 +4953,15 @@ class Parser {
                $nickText = wfEscapeWikiText( $nickname );
                $msgName = $user->isAnon() ? 'signature-anon' : 'signature';
 
-               return wfMessage( $msgName, $userText, $nickText )->inContentLanguage()->title( $this->getTitle() )->text();
+               return wfMessage( $msgName, $userText, $nickText )->inContentLanguage()
+                       ->title( $this->getTitle() )->text();
        }
 
        /**
         * Check that the user's signature contains no bad XML
         *
-        * @param $text String
-        * @return mixed An expanded string, or false if invalid.
+        * @param string $text
+        * @return string|bool An expanded string, or false if invalid.
         */
        function validateSig( $text ) {
                return Xml::isWellFormedXmlFragment( $text ) ? $text : false;
@@ -4761,6 +4980,7 @@ class Parser {
        public function cleanSig( $text, $parsing = false ) {
                if ( !$parsing ) {
                        global $wgTitle;
+                       $magicScopeVariable = $this->lock();
                        $this->startParse( $wgTitle, new ParserOptions, self::OT_PREPROCESS, true );
                }
 
@@ -4803,22 +5023,26 @@ class Parser {
         * Set up some variables which are usually set up in parse()
         * so that an external function can call some class members with confidence
         *
-        * @param $title Title|null
-        * @param $options ParserOptions
-        * @param $outputType
-        * @param $clearState bool
+        * @param Title|null $title
+        * @param ParserOptions $options
+        * @param int $outputType
+        * @param bool $clearState
         */
-       public function startExternalParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
+       public function startExternalParse( Title $title = null, ParserOptions $options,
+               $outputType, $clearState = true
+       ) {
                $this->startParse( $title, $options, $outputType, $clearState );
        }
 
        /**
-        * @param $title Title|null
-        * @param $options ParserOptions
-        * @param $outputType
-        * @param $clearState bool
+        * @param Title|null $title
+        * @param ParserOptions $options
+        * @param int $outputType
+        * @param bool $clearState
         */
-       private function startParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
+       private function startParse( Title $title = null, ParserOptions $options,
+               $outputType, $clearState = true
+       ) {
                $this->setTitle( $title );
                $this->mOptions = $options;
                $this->setOutputType( $outputType );
@@ -5011,7 +5235,7 @@ class Parser {
        /**
         * Get all registered function hook identifiers
         *
-        * @return Array
+        * @return array
         */
        function getFunctionHooks() {
                return array_keys( $this->mFunctionHooks );
@@ -5021,9 +5245,9 @@ class Parser {
         * Create a tag function, e.g. "<test>some stuff</test>".
         * Unlike tag hooks, tag functions are parsed at preprocessor level.
         * Unlike parser functions, their content is not preprocessed.
-        * @param $tag
-        * @param $callback
-        * @param $flags
+        * @param string $tag
+        * @param callable $callback
+        * @param int $flags
         * @throws MWException
         * @return null
         */
@@ -5048,10 +5272,10 @@ class Parser {
         * Replace "<!--LINK-->" link placeholders with actual links, in the buffer
         * Placeholders created in Skin::makeLinkObj()
         *
-        * @param $text string
-        * @param $options int
+        * @param string $text
+        * @param int $options
         *
-        * @return array of link CSS classes, indexed by PDBK.
+        * @return array Array of link CSS classes, indexed by PDBK.
         */
        function replaceLinkHolders( &$text, $options = 0 ) {
                return $this->mLinkHolders->replace( $text );
@@ -5061,8 +5285,8 @@ class Parser {
         * Replace "<!--LINK-->" link placeholders with plain text of links
         * (not HTML-formatted).
         *
-        * @param $text String
-        * @return String
+        * @param string $text
+        * @return string
         */
        function replaceLinkHoldersText( $text ) {
                return $this->mLinkHolders->replaceText( $text );
@@ -5238,7 +5462,7 @@ class Parser {
        }
 
        /**
-        * @param $handler
+        * @param string $handler
         * @return array
         */
        function getImageParams( $handler ) {
@@ -5284,9 +5508,9 @@ class Parser {
        /**
         * Parse image options text and use it to make an image
         *
-        * @param $title Title
-        * @param $options String
-        * @param $holders LinkHolderArray|bool
+        * @param Title $title
+        * @param string $options
+        * @param LinkHolderArray|bool $holders
         * @return string HTML
         */
        function makeImage( $title, $options, $holders = false ) {
@@ -5501,9 +5725,9 @@ class Parser {
        }
 
        /**
-        * @param $caption
-        * @param $holders LinkHolderArray
-        * @return mixed|String
+        * @param string $caption
+        * @param LinkHolderArray|bool $holders
+        * @return mixed|string
         */
        protected function stripAltText( $caption, $holders ) {
                # Strip bad stuff out of the title (tooltip).  We can't just use
@@ -5542,9 +5766,9 @@ class Parser {
         * Callback from the Sanitizer for expanding items found in HTML attribute
         * values, so they can be safely tested and escaped.
         *
-        * @param $text String
-        * @param $frame PPFrame
-        * @return String
+        * @param string $text
+        * @param bool|PPFrame $frame
+        * @return string
         */
        function attributeStripCallback( &$text, $frame = false ) {
                $text = $this->replaceVariables( $text, $frame );
@@ -5558,7 +5782,11 @@ class Parser {
         * @return array
         */
        function getTags() {
-               return array_merge( array_keys( $this->mTransparentTagHooks ), array_keys( $this->mTagHooks ), array_keys( $this->mFunctionTagHooks ) );
+               return array_merge(
+                       array_keys( $this->mTransparentTagHooks ),
+                       array_keys( $this->mTagHooks ),
+                       array_keys( $this->mFunctionTagHooks )
+               );
        }
 
        /**
@@ -5567,7 +5795,7 @@ class Parser {
         * Transparent tag hooks are like regular XML-style tag hooks, except they
         * operate late in the transformation sequence, on HTML instead of wikitext.
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string
         */
@@ -5581,7 +5809,10 @@ class Parser {
                        list( $element, $content, $params, $tag ) = $data;
                        $tagName = strtolower( $element );
                        if ( isset( $this->mTransparentTagHooks[$tagName] ) ) {
-                               $output = call_user_func_array( $this->mTransparentTagHooks[$tagName], array( $content, $params, $this ) );
+                               $output = call_user_func_array(
+                                       $this->mTransparentTagHooks[$tagName],
+                                       array( $content, $params, $this )
+                               );
                        } else {
                                $output = $tag;
                        }
@@ -5597,7 +5828,7 @@ class Parser {
         * External callers should use the getSection and replaceSection methods.
         *
         * @param string $text Page wikitext
-        * @param string $section a section identifier string of the form:
+        * @param string $section A section identifier string of the form:
         *   "<flag1> - <flag2> - ... - <section number>"
         *
         * Currently the only recognised flag is "T", which means the target section number
@@ -5621,6 +5852,8 @@ class Parser {
         */
        private function extractSections( $text, $section, $mode, $newText = '' ) {
                global $wgTitle; # not generally used but removes an ugly failure mode
+
+               $magicScopeVariable = $this->lock();
                $this->startParse( $wgTitle, new ParserOptions, self::OT_PLAIN, true );
                $outText = '';
                $frame = $this->getPreprocessor()->newFrame();
@@ -5735,10 +5968,10 @@ class Parser {
         *
         * If a section contains subsections, these are also returned.
         *
-        * @param string $text text to look in
-        * @param string $section section identifier
-        * @param string $deftext default to return if section is not found
-        * @return string text of the requested section
+        * @param string $text Text to look in
+        * @param string $section Section identifier
+        * @param string $deftext Default to return if section is not found
+        * @return string Text of the requested section
         */
        public function getSection( $text, $section, $deftext = '' ) {
                return $this->extractSections( $text, $section, "get", $deftext );
@@ -5770,7 +6003,7 @@ class Parser {
        /**
         * Get the revision object for $this->mRevisionId
         *
-        * @return Revision|null either a Revision object or null
+        * @return Revision|null Either a Revision object or null
         * @since 1.23 (public since 1.23)
         */
        public function getRevisionObject() {
@@ -5788,6 +6021,7 @@ class Parser {
        /**
         * Get the timestamp associated with the current revision, adjusted for
         * the default server-local timestamp
+        * @return string
         */
        function getRevisionTimestamp() {
                if ( is_null( $this->mRevisionTimestamp ) ) {
@@ -5834,7 +6068,7 @@ class Parser {
        /**
         * Get the size of the revision
         *
-        * @return int|null revision size
+        * @return int|null Revision size
         */
        function getRevisionSize() {
                if ( is_null( $this->mRevisionSize ) ) {
@@ -5884,7 +6118,7 @@ class Parser {
         * Accessor for $mDefaultSort
         * Unlike getDefaultSort(), will return false if none is set
         *
-        * @return string or false
+        * @return string|bool
         */
        public function getCustomDefaultSort() {
                return $this->mDefaultSort;
@@ -5895,7 +6129,7 @@ class Parser {
         * presumably extracted from a heading, for example "Header" from
         * "== Header ==".
         *
-        * @param $text string
+        * @param string $text
         *
         * @return string
         */
@@ -5931,7 +6165,7 @@ class Parser {
         * to create valid section anchors by mimicing the output of the
         * parser when headings are parsed.
         *
-        * @param string $text text string to be stripped of wikitext
+        * @param string $text Text string to be stripped of wikitext
         * for use in a Section anchor
         * @return string Filtered text string
         */
@@ -5957,14 +6191,15 @@ class Parser {
        /**
         * strip/replaceVariables/unstrip for preprocessor regression testing
         *
-        * @param $text string
-        * @param $title Title
-        * @param $options ParserOptions
-        * @param $outputType int
+        * @param string $text
+        * @param Title $title
+        * @param ParserOptions $options
+        * @param int $outputType
         *
         * @return string
         */
        function testSrvus( $text, Title $title, ParserOptions $options, $outputType = self::OT_HTML ) {
+               $magicScopeVariable = $this->lock();
                $this->startParse( $title, $options, $outputType, true );
 
                $text = $this->replaceVariables( $text );
@@ -5974,9 +6209,9 @@ class Parser {
        }
 
        /**
-        * @param $text string
-        * @param $title Title
-        * @param $options ParserOptions
+        * @param string $text
+        * @param Title $title
+        * @param ParserOptions $options
         * @return string
         */
        function testPst( $text, Title $title, ParserOptions $options ) {
@@ -5984,9 +6219,9 @@ class Parser {
        }
 
        /**
-        * @param $text
-        * @param $title Title
-        * @param $options ParserOptions
+        * @param string $text
+        * @param Title $title
+        * @param ParserOptions $options
         * @return string
         */
        function testPreprocess( $text, Title $title, ParserOptions $options ) {
@@ -6004,8 +6239,8 @@ class Parser {
         * two strings will be replaced with the value returned by the callback in
         * each case.
         *
-        * @param $s string
-        * @param $callback
+        * @param string $s
+        * @param callable $callback
         *
         * @return string
         */
@@ -6036,7 +6271,7 @@ class Parser {
        /**
         * Remove any strip markers found in the given text.
         *
-        * @param $text Input string
+        * @param string $text Input string
         * @return string
         */
        function killMarkers( $text ) {
@@ -6055,7 +6290,7 @@ class Parser {
         * unserializeHalfParsedText(). The text can then be safely incorporated into
         * the return value of a parser hook.
         *
-        * @param $text string
+        * @param string $text
         *
         * @return array
         */
@@ -6084,7 +6319,7 @@ class Parser {
         *
         * @param array $data Serialized data
         * @throws MWException
-        * @return String
+        * @return string
         */
        function unserializeHalfParsedText( $data ) {
                if ( !isset( $data['version'] ) || $data['version'] != self::HALF_PARSED_VERSION ) {
@@ -6107,7 +6342,7 @@ class Parser {
         * serializeHalfParsedText(), is compatible with the current version of the
         * parser.
         *
-        * @param $data Array
+        * @param array $data
         *
         * @return bool
         */
@@ -6118,7 +6353,7 @@ class Parser {
        /**
         * Parsed a width param of imagelink like 300px or 200x300px
         *
-        * @param $value String
+        * @param string $value
         *
         * @return array
         * @since 1.20
@@ -6142,4 +6377,28 @@ class Parser {
                }
                return $parsedWidthParam;
        }
+
+       /**
+        * Lock the current instance of the parser.
+        *
+        * This is meant to stop someone from calling the parser
+        * recursively and messing up all the strip state.
+        *
+        * @throws MWException If parser is in a parse
+        * @return ScopedCallback The lock will be released once the return value goes out of scope.
+        */
+       protected function lock() {
+               if ( $this->mInParse ) {
+                       throw new MWException( "Parser state cleared while parsing. "
+                               . "Did you call Parser::parse recursively?" );
+               }
+               $this->mInParse = true;
+
+               $that = $this;
+               $recursiveCheck = new ScopedCallback( function() use ( $that ) {
+                       $that->mInParse = false;
+               } );
+
+               return $recursiveCheck;
+       }
 }