Recently I encountered what I thought was a bug in my code, but it turned out to be something much more interesting.
First, some background: Here at Vistaprint we have a number of custom extensions written for our internal-documentation wiki. One of those categorizes articles programmatically - you call it from the code and it will auto-categorize the page. Something along the effect of: $c = new Categorizer; $c->addToCategory( 'my-message-key' );
Whenever this code was called it broke the Cite extension. Specifically, anything defined with <ref></ref> would not show up in the <references /> section below. Doing some digging I found this issue:
1. Our custom extension parsed a message in the middle of a page (while the page was being parsed in the code)
2. Parsing a message called MessageCache::parse, by way of wfMessage() and the Message object
3. The MessageCache object clones the global parser and parses the message
4. Parsing the message means that the (cloned) parser calls Parser::clearState
The problem is that calling Parser::clearState() on the cloned parser object (a property of MessageCache) also clears the state of the global parser object. This might be due to two things:
1. PHP makes shallow-copies of objects when cloning and not deep-copies [1].
2. When the Cite extension inserts itself into a parser it sets up a callback to the 'ParserClearState' hook. When this callback is run, because of #1 (no deep-copying) it effectively gets run for all clones of the parser.
This is arguably a bug in MediaWiki: cloning a parser does not create a totally separate object with its own state. I have found a number of bug-reports that seem to be related to this issue [2][3][4]. Before I go off and submit a bunch of code, I'd like the input from the community.
Thoughts? -Daniel ( User:DanielRenfro )
References: [1] http://php.net/manual/en/language.oop5.cloning.php [2] https://bugzilla.wikimedia.org/show_bug.cgi?id=34589 [3] https://bugzilla.wikimedia.org/show_bug.cgi?id=32368 [4] https://bugzilla.wikimedia.org/show_bug.cgi?id=47291
Hi Daniel,
"When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. Any properties that are references to other variables, will remain references."
http://php.net/manual/en/language.oop5.cloning.php
You might have look creating a "clone" in the following manner:
$clone = unserialize( serialize( $parser ) );
I'm not saying that's the best solution, but it's a quick and dirty solution that sometimes does what you need (namely a deep copy).
Cheers, Rob.
On 13-06-18 02:17 PM, Daniel Renfro wrote:
Recently I encountered what I thought was a bug in my code, but it turned out to be something much more interesting.
First, some background: Here at Vistaprint we have a number of custom extensions written for our internal-documentation wiki. One of those categorizes articles programmatically - you call it from the code and it will auto-categorize the page. Something along the effect of: $c = new Categorizer; $c->addToCategory( 'my-message-key' );
Whenever this code was called it broke the Cite extension. Specifically, anything defined with <ref></ref> would not show up in the <references /> section below. Doing some digging I found this issue:
Our custom extension parsed a message in the middle of a page (while the page was being parsed in the code)Parsing a message called MessageCache::parse, by way of wfMessage() and the Message objectThe MessageCache object clones the global parser and parses the messageParsing the message means that the (cloned) parser calls Parser::clearStateThe problem is that calling Parser::clearState() on the cloned parser object (a property of MessageCache) also clears the state of the global parser object. This might be due to two things:
PHP makes shallow-copies of objects when cloning and not deep-copies [1].When the Cite extension inserts itself into a parser it sets up a callback to the 'ParserClearState' hook. When this callback is run, because of #1 (no deep-copying) it effectively gets run for all clones of the parser.This is arguably a bug in MediaWiki: cloning a parser does not create a totally separate object with its own state. I have found a number of bug-reports that seem to be related to this issue [2][3][4]. Before I go off and submit a bunch of code, I'd like the input from the community.
Thoughts? -Daniel ( User:DanielRenfro )
References: [1] http://php.net/manual/en/language.oop5.cloning.php [2] https://bugzilla.wikimedia.org/show_bug.cgi?id=34589 [3] https://bugzilla.wikimedia.org/show_bug.cgi?id=32368 [4] https://bugzilla.wikimedia.org/show_bug.cgi?id=47291
MediaWiki-l mailing list MediaWiki-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-l
On 19/06/13 04:17, Daniel Renfro wrote:
This is arguably a bug in MediaWiki: cloning a parser does not create a totally separate object with its own state. I have found a number of bug-reports that seem to be related to this issue [2][3][4]. Before I go off and submit a bunch of code, I'd like the input from the community.
I don't think a lot of code would be needed. There is already a ParserCloned hook that Cite can use to fix this, without any changes to the core. It was introduced in November 2012.
-- Tim Starling
mediawiki-l@lists.wikimedia.org