'TestAutoloadedLocalClass' => __DIR__ . '/../data/autoloader/TestAutoloadedLocalClass.php',
'TestAutoloadedCamlClass' => __DIR__ . '/../data/autoloader/TestAutoloadedCamlClass.php',
'TestAutoloadedSerializedClass' => __DIR__ . '/../data/autoloader/TestAutoloadedSerializedClass.php',
- 'TestAutoloadedAliasedClass' => 'alias:TestAutoloadedAliasedClassNew',
- 'TestAutoloadedAliasedClassDeprecated' => 'alias:TestAutoloadedAliasedClassNew?v=1.1',
- 'TestAutoloadedAliasedClassNew' => __DIR__ . '/../data/autoloader/TestAutoloadedAliasedClassNew.php',
);
$this->setMwGlobals( 'wgAutoloadLocalClasses', $this->testLocalClasses + $wgAutoloadLocalClasses );
AutoLoader::resetAutoloadLocalClassesLower();
protected static function checkAutoLoadConf() {
global $wgAutoloadLocalClasses, $wgAutoloadClasses, $IP;
- $supportsParsekit = function_exists( 'parsekit_compile_file' );
// wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php
$expected = $wgAutoloadLocalClasses + $wgAutoloadClasses;
$actual = array();
- // Check aliases
- foreach ( $expected as $class => $file ) {
- if ( substr( $file, 0, 6 ) !== 'alias:' ) {
- // Not an alias, so should be an actual file
- $files[] = $file;
- } else {
- $newClass = substr( $file, 6, strcspn( $file, '?', 6 ) );
- if ( isset( $expected[$newClass] ) ) {
- if ( substr( $expected[$newClass], 0, 6 ) !== 'alias:' ) {
- // Alias pointing to an existing MediaWiki class
- $actual[$class] = $file;
- }
- }
- }
- }
-
- $files = array_unique( $files );
+ $files = array_unique( $expected );
foreach ( $files as $file ) {
// Only prefix $IP if it doesn't have it already.
} else {
$filePath = $file;
}
- if ( $supportsParsekit ) {
- $parseInfo = parsekit_compile_file( "$filePath" );
- $classes = array_keys( $parseInfo['class_table'] );
- } else {
- $contents = file_get_contents( "$filePath" );
- $m = array();
- preg_match_all( '/\n\s*(?:final)?\s*(?:abstract)?\s*(?:class|interface)\s+([a-zA-Z0-9_]+)/', $contents, $m, PREG_PATTERN_ORDER );
- $classes = $m[1];
+
+ $contents = file_get_contents( $filePath );
+
+ // We could use token_get_all() here, but this is faster
+ $matches = array();
+ preg_match_all( '/
+ ^ [\t ]* (?:
+ (?:final\s+)? (?:abstract\s+)? (?:class|interface) \s+
+ (?P<class> [a-zA-Z0-9_]+)
+ |
+ class_alias \s* \( \s*
+ ([\'"]) (?P<original> [^\'"]+) \g{-2} \s* , \s*
+ ([\'"]) (?P<alias> [^\'"]+ ) \g{-2} \s*
+ \) \s* ;
+ )
+ /imx', $contents, $matches, PREG_SET_ORDER );
+
+ $classesInFile = array();
+ $aliasesInFile = array();
+
+ foreach ( $matches as $match ) {
+ if ( !empty( $match['class'] ) ) {
+ $actual[$match['class']] = $file;
+ $classesInFile[$match['class']] = true;
+ } else {
+ $aliasesInFile[$match['alias']] = $match['original'];
+ }
}
- foreach ( $classes as $class ) {
- $actual[$class] = $file;
+
+ // Only accept aliases for classes in the same file, because for correct
+ // behavior, all aliases for a class must be set up when the class is loaded
+ // (see <https://bugs.php.net/bug.php?id=61422>).
+ foreach ( $aliasesInFile as $alias => $class ) {
+ if ( isset( $classesInFile[$class] ) ) {
+ $actual[$alias] = $file;
+ } else {
+ $actual[$alias] = "[original class not in $file]";
+ }
}
}
$this->assertFalse( $uncerealized instanceof __PHP_Incomplete_Class,
"unserialize() can load classes case-insensitively." );
}
-
- function testAliasedClass() {
- $this->assertSame( 'TestAutoloadedAliasedClassNew',
- get_class( new TestAutoloadedAliasedClass ) );
- }
-
- function testAliasedClassDeprecated() {
- wfSuppressWarnings();
- $this->assertSame( 'TestAutoloadedAliasedClassNew',
- get_class( new TestAutoloadedAliasedClassDeprecated ) );
- wfRestoreWarnings();
- }
}