jenkins-bot has submitted this change and it was merged.
Change subject: Minor optimization to the AutoLoader
......................................................................
Minor optimization to the AutoLoader
When MediaWiki autoloading fails, we should gracefully return false.
Instead, we have been calling strtolower roughly 1,000 times in the hope
of finding a case-insensitive match.
This patch preserves the legacy case-insensitivity, but improves its
performance by approximately 100x, by storing the case-insensitive class
lookups as a static variable.
There is a new global $wgAutoloadAttemptLowercase which will switch the
behavior if desired. The default is to support case-insensitive loading.
Change-Id: Ifb12e05614a48390b730167e9d4ddcd8545db764
---
M includes/AutoLoader.php
M includes/DefaultSettings.php
A tests/phpunit/data/autoloader/TestAutoloadedCamlClass.php
A tests/phpunit/data/autoloader/TestAutoloadedClass.php
A tests/phpunit/data/autoloader/TestAutoloadedLocalClass.php
A tests/phpunit/data/autoloader/TestAutoloadedSerializedClass.php
M tests/phpunit/structure/AutoLoaderTest.php
7 files changed, 98 insertions(+), 13 deletions(-)
Approvals:
Tim Starling: Looks good to me, approved
jenkins-bot: Verified
diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 0706fe3..dbba500 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
@@ -1136,6 +1136,8 @@
);
class AutoLoader {
+ static $autoloadLocalClassesLower = null;
+
/**
* autoload - take a class name and attempt to load it
*
@@ -1145,7 +1147,8 @@
* as well.
*/
static function autoload( $className ) {
- global $wgAutoloadClasses, $wgAutoloadLocalClasses;
+ global $wgAutoloadClasses, $wgAutoloadLocalClasses,
+ $wgAutoloadAttemptLowercase;
// Workaround for PHP bug
<https://bugs.php.net/bug.php?id=49143> (5.3.2. is broken, it's
// fixed in 5.3.6). Strip leading backslashes from class names.
When namespaces are used,
@@ -1160,28 +1163,39 @@
$filename = $wgAutoloadLocalClasses[$className];
} elseif ( isset( $wgAutoloadClasses[$className] ) ) {
$filename = $wgAutoloadClasses[$className];
- } else {
- # Try a different capitalisation
- # The case can sometimes be wrong when unserializing
PHP 4 objects
+ } elseif ( $wgAutoloadAttemptLowercase ) {
+ /*
+ * Try a different capitalisation.
+ *
+ * PHP 4 objects are always serialized with the
classname coerced to lowercase,
+ * and we are plagued with several legacy uses created
by MediaWiki < 1.5, see
+ * https://wikitech.wikimedia.org/wiki/Text_storage_data
+ */
$filename = false;
$lowerClass = strtolower( $className );
- foreach ( $wgAutoloadLocalClasses as $class2 => $file2
) {
- if ( strtolower( $class2 ) == $lowerClass ) {
- $filename = $file2;
- }
+ if ( self::$autoloadLocalClassesLower === null ) {
+ self::$autoloadLocalClassesLower =
array_change_key_case( $wgAutoloadLocalClasses, CASE_LOWER );
}
- if ( !$filename ) {
+ if ( isset(
self::$autoloadLocalClassesLower[$lowerClass] ) ) {
if ( function_exists( 'wfDebug' ) ) {
- wfDebug( "Class {$className} not found;
skipped loading\n" );
+ wfDebug( "Class {$className} was loaded
using incorrect case.\n" );
}
-
- # Give up
- return false;
+ $filename =
self::$autoloadLocalClassesLower[$lowerClass];
}
}
+ if ( !$filename ) {
+ if ( function_exists( 'wfDebug' ) ) {
+ # FIXME: This is not very polite. Assume we do
not manage the class.
+ wfDebug( "Class {$className} not found; skipped
loading\n" );
+ }
+
+ # Give up
+ return false;
+ }
+
# Make an absolute path, this improves performance by avoiding
some stat calls
if ( substr( $filename, 0, 1 ) != '/' && substr( $filename, 1,
1 ) != ':' ) {
global $IP;
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index dbdd89e..bf2d2fd 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -5954,6 +5954,13 @@
$wgAutoloadClasses = array();
/**
+ * Switch controlling legacy case-insensitive classloading.
+ * Do not disable if your wiki must support data created by PHP4, or by
+ * MediaWiki 1.4 or earlier.
+ */
+$wgAutoloadAttemptLowercase = true;
+
+/**
* An array of extension types and inside that their names, versions, authors,
* urls, descriptions and pointers to localized description msgs. Note that
* the version, url, description and descriptionmsg key can be omitted.
diff --git a/tests/phpunit/data/autoloader/TestAutoloadedCamlClass.php
b/tests/phpunit/data/autoloader/TestAutoloadedCamlClass.php
new file mode 100644
index 0000000..6dfce7a
--- /dev/null
+++ b/tests/phpunit/data/autoloader/TestAutoloadedCamlClass.php
@@ -0,0 +1,4 @@
+<?php
+
+class TestAutoloadedCamlClass {
+}
diff --git a/tests/phpunit/data/autoloader/TestAutoloadedClass.php
b/tests/phpunit/data/autoloader/TestAutoloadedClass.php
new file mode 100644
index 0000000..9ceedf6
--- /dev/null
+++ b/tests/phpunit/data/autoloader/TestAutoloadedClass.php
@@ -0,0 +1,4 @@
+<?php
+
+class TestAutoloadedClass {
+}
diff --git a/tests/phpunit/data/autoloader/TestAutoloadedLocalClass.php
b/tests/phpunit/data/autoloader/TestAutoloadedLocalClass.php
new file mode 100644
index 0000000..1b397cd
--- /dev/null
+++ b/tests/phpunit/data/autoloader/TestAutoloadedLocalClass.php
@@ -0,0 +1,4 @@
+<?php
+
+class TestAutoloadedLocalClass {
+}
diff --git a/tests/phpunit/data/autoloader/TestAutoloadedSerializedClass.php
b/tests/phpunit/data/autoloader/TestAutoloadedSerializedClass.php
new file mode 100644
index 0000000..80b9d58
--- /dev/null
+++ b/tests/phpunit/data/autoloader/TestAutoloadedSerializedClass.php
@@ -0,0 +1,4 @@
+<?php
+
+class TestAutoloadedSerializedClass {
+}
diff --git a/tests/phpunit/structure/AutoLoaderTest.php
b/tests/phpunit/structure/AutoLoaderTest.php
index 205ea36..f5ff1d9 100644
--- a/tests/phpunit/structure/AutoLoaderTest.php
+++ b/tests/phpunit/structure/AutoLoaderTest.php
@@ -1,6 +1,26 @@
<?php
class AutoLoaderTest extends MediaWikiTestCase {
+ protected function setUp() {
+ global $wgAutoloadLocalClasses, $wgAutoloadClasses;
+
+ parent::setUp();
+
+ // Fancy dance to trigger a rebuild of
AutoLoader::$autoloadLocalClassesLower
+ $this->testLocalClasses = array(
+ 'TestAutoloadedLocalClass' => __DIR__ .
'/../data/autoloader/TestAutoloadedLocalClass.php',
+ 'TestAutoloadedCamlClass' => __DIR__ .
'/../data/autoloader/TestAutoloadedCamlClass.php',
+ 'TestAutoloadedSerializedClass' => __DIR__ .
'/../data/autoloader/TestAutoloadedSerializedClass.php',
+ );
+ $this->setMwGlobals( 'wgAutoloadLocalClasses',
$this->testLocalClasses + $wgAutoloadLocalClasses );
+ InstrumentedAutoLoader::resetAutoloadLocalClassesLower();
+
+ $this->testExtensionClasses = array(
+ 'TestAutoloadedClass' => __DIR__ .
'/../data/autoloader/TestAutoloadedClass.php',
+ );
+ $this->setMwGlobals( 'wgAutoloadClasses',
$this->testExtensionClasses + $wgAutoloadClasses );
+ }
+
/**
* Assert that there were no classes loaded that are not registered
with the AutoLoader.
*
@@ -53,4 +73,32 @@
'actual' => $actual,
);
}
+
+ function testCoreClass() {
+ $this->assertTrue( class_exists( 'TestAutoloadedLocalClass' ) );
+ }
+
+ function testExtensionClass() {
+ $this->assertTrue( class_exists( 'TestAutoloadedClass' ) );
+ }
+
+ function testWrongCaseClass() {
+ $this->assertTrue( class_exists( 'testautoLoadedcamlCLASS' ) );
+ }
+
+ function testWrongCaseSerializedClass() {
+ $dummyCereal = 'O:29:"testautoloadedserializedclass":0:{}';
+ $uncerealized = unserialize( $dummyCereal );
+ $this->assertFalse( $uncerealized instanceof
__PHP_Incomplete_Class,
+ "unserialize() can load classes case-insensitively.");
+ }
+}
+
+/**
+ * Cheater to poke protected members
+ */
+class InstrumentedAutoLoader extends AutoLoader {
+ static function resetAutoloadLocalClassesLower() {
+ self::$autoloadLocalClassesLower = null;
+ }
}
--
To view, visit https://gerrit.wikimedia.org/r/92170
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ifb12e05614a48390b730167e9d4ddcd8545db764
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Adamw <[email protected]>
Gerrit-Reviewer: Adamw <[email protected]>
Gerrit-Reviewer: Hashar <[email protected]>
Gerrit-Reviewer: Parent5446 <[email protected]>
Gerrit-Reviewer: PleaseStand <[email protected]>
Gerrit-Reviewer: Tim Starling <[email protected]>
Gerrit-Reviewer: Tychay <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits