$cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
// approximate error count: 22
"PhanAccessMethodInternal",
- // approximate error count: 22
- "PhanCommentParamWithoutRealParam",
// approximate error count: 19
"PhanParamReqAfterOpt",
- // approximate error count: 20
- "PhanParamSignatureMismatch",
// approximate error count: 110
"PhanParamTooMany",
// approximate error count: 63
"PhanTypeArraySuspicious",
- // approximate error count: 28
- "PhanTypeArraySuspiciousNullable",
- // approximate error count: 22
- "PhanTypeComparisonFromArray",
// approximate error count: 88
"PhanTypeInvalidDimOffset",
// approximate error count: 60
"PhanTypeMismatchArgument",
- // approximate error count: 20
- "PhanTypeMismatchArgumentInternal",
- // approximate error count: 40
- "PhanTypeMismatchProperty",
// approximate error count: 36
"PhanUndeclaredConstant",
// approximate error count: 219
}
public function stop() {
}
- public function getLog() {
+ public function getLog() : ExcimerLog {
}
public function flush() {
}
}
function formatCollapsed() {
}
+ /**
+ * @return array[]
+ */
function aggregateByFunction() {
}
+ /**
+ * @return int
+ */
function getEventCount() {
}
function current() {
Starting with MediaWiki 1.2.0, it's possible to install and configure the wiki
"in-place", as long as you have the necessary prerequisites available.
-Required software:
-* Web server with PHP 7.0.0 or HHVM 3.18.5 or higher.
+Required software as of MediaWiki 1.34.0:
+
+* Web server with PHP 7.0.13 or higher, plus the following extesnsions:
+** ctype
+** dom
+** fileinfo
+** iconv
+** json
+** mbstring
+** xml
* A SQL server, the following types are supported
** MySQL 5.5.8 or higher
** PostgreSQL 9.2 or higher
== Compatibility ==
MediaWiki 1.34 requires PHP 7.0.13 or later. Although HHVM 3.18.5 or later is
supported, it is generally advised to use PHP 7.0.13 or later for long term
-support.
+support. It also requires the following PHP extensions:
+
+* ctype
+* dom
+* fileinfo
+* iconv
+* json
+* mbstring
+* xml
MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used,
but support for them is somewhat less mature.
"composer/semver": "1.5.0",
"cssjanus/cssjanus": "1.3.0",
"ext-ctype": "*",
+ "ext-dom": "*",
"ext-fileinfo": "*",
"ext-iconv": "*",
"ext-json": "*",
* $wgTiffThumbnailType = [ 'jpg', 'image/jpeg' ];
* @endcode
*/
-$wgTiffThumbnailType = false;
+$wgTiffThumbnailType = [];
/**
* If rendered thumbnail files are older than this timestamp, they
/**
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function getValues() {
return $this->data;
if ( isset( $ctx['forwarded_for'] ) ||
isset( $ctx['client_ip'] ) ||
isset( $ctx['from'] ) ) {
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
$ctx['proxy'] = $_SERVER['REMOTE_ADDR'];
}
$result = unpack( $format, $data );
Wikimedia\restoreWarnings();
+ // @phan-suppress-next-line PhanTypeComparisonFromArray Phan issue #3160
if ( $result === false ) {
// If it cannot extract the packed data.
throw new MWException( "unpack could not unpack binary data" );
Profiler::instance()->logDataPageOutputOnly();
} catch ( Exception $e ) {
// An error may already have been shown in run(), so just log it to be safe
- MWExceptionHandler::rollbackMasterChangesAndLog( $e );
+ MWExceptionHandler::logException( $e );
}
// Disable WebResponse setters for post-send processing (T191537).
* @todo document
*/
class OutputPage extends ContextSource {
- /** @var array Should be private. Used with addMeta() which adds "<meta>" */
+ /** @var string[][] Should be private. Used with addMeta() which adds "<meta>" */
protected $mMetatags = [];
/** @var array */
* @param string $text Wikitext
* @param Title $title
* @param bool $linestart Is this the start of a line?
- * @param bool $tidy Whether to use tidy.
- * Setting this to false (or omitting it) is deprecated
- * since 1.32; all wikitext should be tidied.
* @param bool $interface Whether it is an interface message
* (for example disables conversion)
* @param string $wrapperClass if not empty, wraps the output in
* a `<div class="$wrapperClass">`
- * @private
*/
private function addWikiTextTitleInternal(
$text, Title $title, $linestart, $interface, $wrapperClass = null
/** @var NamespaceInfo */
private $nsInfo;
- /** @var string[] Cached results of getAllRights() */
- private $allRights = false;
+ /** @var string[]|null Cached results of getAllRights() */
+ private $allRights;
/** @var string[][] Cached user rights */
private $usersRights = null;
* Check if user is allowed to make any action
*
* @param UserIdentity $user
- * // TODO: HHVM can't create mocks with variable params @param string ...$actions
+ * // TODO: HHVM bug T228695#5450847 @param string ...$actions
+ * @suppress PhanCommentParamWithoutRealParam
* @return bool True if user is allowed to perform *any* of the given actions
* @since 1.34
*/
* Check if user is allowed to make all actions
*
* @param UserIdentity $user
- * // TODO: HHVM can't create mocks with variable params @param string ...$actions
+ * // TODO: HHVM bug T228695#5450847 @param string ...$actions
+ * @suppress PhanCommentParamWithoutRealParam
* @return bool True if user is allowed to perform *all* of the given actions
* @since 1.34
*/
* @return string[] Array of permission names
*/
public function getAllPermissions() {
- if ( $this->allRights === false ) {
+ if ( $this->allRights === null ) {
if ( count( $this->options->get( 'AvailableRights' ) ) ) {
$this->allRights = array_unique( array_merge(
$this->coreRights,
* better served by an HTTP header parsing library which provides the full
* parse tree.
*
- * @param string $name The header name
* @param string|string[] $value The input header value
* @return array
*/
$wgMemc = ObjectCache::getLocalClusterInstance();
$messageMemc = wfGetMessageCacheStorage();
-wfDebugLog( 'caches',
- 'cluster: ' . get_class( $wgMemc ) .
- ', WAN: ' . ( $wgMainWANCache === CACHE_NONE ? 'CACHE_NONE' : $wgMainWANCache ) .
- ', stash: ' . $wgMainStash .
- ', message: ' . get_class( $messageMemc ) .
- ', session: ' . get_class( ObjectCache::getInstance( $wgSessionCacheType ) )
-);
-
// Most of the config is out, some might want to run hooks here.
Hooks::run( 'SetupAfterCache' );
/** @var bool Whether a page has any subpages */
private $mHasSubpages;
- /** @var bool The (string) language code of the page's language and content code. */
- private $mPageLanguage = false;
+ /** @var array|null The (string) language code of the page's language and content code. */
+ private $mPageLanguage;
/** @var string|bool|null The page language code from the database, null if not saved in
* the database or false if not loaded, yet.
$this->mLatestID = false;
$this->mContentModel = false;
$this->mEstimateRevisions = null;
- $this->mPageLanguage = false;
+ $this->mPageLanguage = null;
$this->mDbPageLanguage = false;
$this->mIsBigDeletion = null;
}
* @ingroup HTTP
*/
class WebRequest {
- protected $data, $headers = [];
+ /** @var array */
+ protected $data;
+ /** @var array */
+ protected $headers = [];
/**
* Flag to make WebRequest::getHeader return an array of values.
/**
* Clean up a field array for output
- * @param ApiBase $module For context and parameters 'mergerequestfields'
- * and 'messageformat'
* @param array $fields
* @return array
*/
/** @var array Maps extension paths to info arrays */
private static $extensionInfo = null;
- /** @var int[][][] Cache for self::filterIDs() */
+ /** @var stdClass[][] Cache for self::filterIDs() */
private static $filterIDsCache = [];
/** $var array Map of web UI block messages to corresponding API messages and codes */
/** @var Title $newTitle */
foreach ( $titles as $id => $newTitle ) {
- if ( !isset( $titles[$id - 1] ) ) {
- $titles[$id - 1] = $oldTitle;
- }
+ $titles[ $id - 1 ] = $titles[ $id - 1 ] ?? $oldTitle;
$redirValues[] = [
'from' => $titles[$id - 1]->getPrefixedText(),
* @param int $successCount
* @param array $pageInfo
* @return void
+ * @suppress PhanParamSignatureMismatch
*/
public function reportPage( $title, $foreignTitle, $revisionCount, $successCount, $pageInfo ) {
// Add a result entry
* @param string $search the search query
* @param array $params api request params
* @return array search results. Keys are integers.
+ * @phan-return array<array{title:Title,extract:false,image:false,url:string}>
+ * Note that phan annotations don't support keys containing a space.
*/
private function search( $search, array $params ) {
$searchEngine = $this->buildSearchEngine( $params );
if ( is_string( $r['extract'] ) && $r['extract'] !== '' ) {
$item['Description'] = $r['extract'];
}
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
if ( is_array( $r['image'] ) && isset( $r['image']['source'] ) ) {
$item['Image'] = array_intersect_key( $r['image'], $imageKeys );
}
}
}
- $fit = $result->addValue( [ 'query', $this->getModuleName() ],
- null, $data[$u] );
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
+ $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $data[$u] );
if ( !$fit ) {
if ( $useNames ) {
$this->setContinueEnumParameter( 'users',
return;
}
- // The user will abort the AJAX request by pressing "save", so ignore that
- ignore_user_abort( true );
-
if ( $user->pingLimiter( 'stashedit' ) ) {
$status = 'ratelimited';
} else {
}
$options['sensitive'] = !empty( $options['sensitive'] );
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
+ $type = $options['type'];
if ( !array_key_exists( $name, $merged ) ) {
$merged[$name] = $options;
- } elseif ( $merged[$name]['type'] !== $options['type'] ) {
+ } elseif ( $merged[$name]['type'] !== $type ) {
throw new \UnexpectedValueException( "Field type conflict for \"$name\", " .
- "\"{$merged[$name]['type']}\" vs \"{$options['type']}\""
+ "\"{$merged[$name]['type']}\" vs \"$type\""
);
} else {
if ( isset( $options['options'] ) ) {
* Function that gets called when initialization is done.
*
* @since 1.20
- * @var callable
+ * @var callable|null
*/
- protected $onInitHandler = false;
+ protected $onInitHandler;
/**
* Elements to build a cache key with.
$this->hasCached = is_array( $cachedChunks );
$this->cachedChunks = $this->hasCached ? $cachedChunks : [];
- if ( $this->onInitHandler !== false ) {
+ if ( $this->onInitHandler !== null ) {
call_user_func( $this->onInitHandler, $this->hasCached );
}
}
$class = $wgParserConf['class'];
if ( $class == ParserDiffTest::class ) {
# Uncloneable
+ // @phan-suppress-next-line PhanTypeMismatchProperty
$this->mParser = new $class( $wgParserConf );
} else {
$this->mParser = clone $parser;
*/
class LCStoreCDB implements LCStore {
- /** @var Reader[] */
+ /** @var Reader[]|false[] */
private $readers;
/** @var Writer */
if ( in_array( $key, self::$mergeableMapKeys ) ) {
$value = $value + $fallbackValue;
} elseif ( in_array( $key, self::$mergeableListKeys ) ) {
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$value = array_unique( array_merge( $fallbackValue, $value ) );
} elseif ( in_array( $key, self::$mergeableAliasListKeys ) ) {
$value = array_merge_recursive( $value, $fallbackValue );
if ( !$code ) {
throw new MWException( "Invalid language code requested" );
}
- $this->recachedLangs[$code] = true;
+ $this->recachedLangs[ $code ] = true;
# Initial values
$initialData = array_fill_keys( self::$allKeys, null );
# Load the primary localisation from the source file
$data = $this->readSourceFilesAndRegisterDeps( $code, $deps );
- if ( $data === false ) {
- $this->logger->debug( __METHOD__ . ": no localisation file for $code, using fallback to en" );
- $coreData['fallback'] = 'en';
- } else {
- $this->logger->debug( __METHOD__ . ": got localisation for $code from source" );
+ $this->logger->debug( __METHOD__ . ": got localisation for $code from source" );
- # Merge primary localisation
- foreach ( $data as $key => $value ) {
- $this->mergeItem( $key, $coreData[$key], $value );
- }
+ # Merge primary localisation
+ foreach ( $data as $key => $value ) {
+ $this->mergeItem( $key, $coreData[ $key ], $value );
}
# Fill in the fallback if it's not there already
# Load the secondary localisation from the source file to
# avoid infinite cycles on cyclic fallbacks
$fbData = $this->readSourceFilesAndRegisterDeps( $csCode, $deps );
- if ( $fbData !== false ) {
- # Only merge the keys that make sense to merge
- foreach ( self::$allKeys as $key ) {
- if ( !isset( $fbData[$key] ) ) {
- continue;
- }
-
- if ( is_null( $coreData[$key] ) || $this->isMergeableKey( $key ) ) {
- $this->mergeItem( $key, $csData[$key], $fbData[$key] );
- }
+ # Only merge the keys that make sense to merge
+ foreach ( self::$allKeys as $key ) {
+ if ( !isset( $fbData[ $key ] ) ) {
+ continue;
+ }
+
+ if ( is_null( $coreData[ $key ] ) || $this->isMergeableKey( $key ) ) {
+ $this->mergeItem( $key, $csData[ $key ], $fbData[ $key ] );
}
}
}
public $mExtra = [];
/**
- * @var Title
+ * @var Title|false
*/
public $mTitle = false;
/**
- * @var User
+ * @var User|false
*/
private $mPerformer = false;
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key /* $args */ ) {
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,... Arguments to wfMessage
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key ) {
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key ) {
* @param Diff $diff A Diff object.
*
* @return array[] List of associative arrays, each describing a difference.
+ * @suppress PhanParamSignatureMismatch
*/
public function format( $diff ) {
$oldline = 1;
public $type;
/**
- * @var string[]
+ * @var string[]|false
*/
public $orig;
/**
- * @var string[]
+ * @var string[]|false
*/
public $closing;
/**
* @param DumpOutput &$sink
- * @param array $param
+ * @param string $param
* @throws MWException
*/
function __construct( &$sink, $param ) {
"NS_CATEGORY" => NS_CATEGORY,
"NS_CATEGORY_TALK" => NS_CATEGORY_TALK ];
- if ( $param { 0 } == '!' ) {
+ if ( $param[0] == '!' ) {
$this->invert = true;
$param = substr( $param, 1 );
}
*/
class DumpPipeOutput extends DumpFileOutput {
protected $command, $filename;
+ /** @var resource|bool */
protected $procOpenResource = false;
/**
/**
* @param string $virtualUrl
- * @return false
+ * @return array
*/
function getFileProps( $virtualUrl ) {
- return false;
+ return [];
}
/**
? count( $data['query']['redirects'] ) - 1
: -1;
if ( $lastRedirect >= 0 ) {
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
$newtitle = Title::newFromText( $data['query']['redirects'][$lastRedirect]['to'] );
$img = new self( $newtitle, $repo, $info, true );
$img->redirectedFrom( $title->getDBkey() );
protected $mHideBadImages;
/**
- * @var Parser Registered parser object for output callbacks
+ * @var Parser|false Registered parser object for output callbacks
*/
public $mParser;
/** @var array */
protected $mAttribs = [];
- /** @var bool */
- private static $modeMapping = false;
+ /** @var array */
+ private static $modeMapping;
/**
* Get a new image gallery. This is the method other callers
}
private static function loadModes() {
- if ( self::$modeMapping === false ) {
+ if ( self::$modeMapping === null ) {
self::$modeMapping = [
'traditional' => TraditionalImageGallery::class,
'nolines' => NolinesImageGallery::class,
* Improves compression ratio by concatenating like objects before gzipping
*/
class ConcatenatedGzipHistoryBlob implements HistoryBlob {
- public $mVersion = 0, $mCompressed = false, $mItems = [], $mDefaultHash = '';
+ public $mVersion = 0;
+ public $mCompressed = false;
+ /**
+ * @var array|string
+ * @fixme Why are some methods treating it as an array, and others as a string, unconditionally?
+ */
+ public $mItems = [];
+ public $mDefaultHash = '';
public $mSize = 0;
public $mMaxSize = 10000000;
public $mMaxCount = 100;
*
* @param string $displayFormat
* @param mixed $arguments,... Additional arguments to pass to the constructor.
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return HTMLForm
*/
public static function factory( $displayFormat/*, $arguments...*/ ) {
* be a subclass of this.
*/
abstract class HTMLFormField {
+ /** @var array|array[] */
public $mParams;
protected $mValidationCallback;
* The old name of autocomplete-data[-messages] was autocomplete[-messages] which is still
* recognized but deprecated since MediaWiki 1.29 since it conflicts with how autocomplete is
* used in HTMLTextField.
+ *
+ * @phan-file-suppress PhanTypeMismatchProperty This is doing weird things with mClass
*/
class HTMLAutoCompleteSelectField extends HTMLTextField {
protected $autocompleteData = [];
* mParams['columns'] is an array with column labels as keys and column tags as values.
*
* @param array $value Array of the options that should be checked
+ * @suppress PhanParamSignatureMismatch
*
* @return string
*/
* @since 1.28
* @param string[] $value
* @return string|OOUI\CheckboxMultiselectInputWidget
+ * @suppress PhanParamSignatureMismatch
*/
public function getInputOOUI( $value ) {
$this->mParent->getOutput()->addModules( 'oojs-ui-widgets' );
protected $handler = null;
protected $sink = null;
+ /** @var array */
protected $guzzleOptions = [ 'http_errors' => false ];
/**
*
* @param string|string[]|MessageSpecifier $key
* @param mixed $param,... Parameters as strings.
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
*
* @return Message
*/
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $params,... Normal message parameters
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key /*...*/ );
throw new InvalidArgumentException( "Invalid ring source specified." );
}
+ // Short-circuit for the common single-location case. Note that if there was only one
+ // location and it was ejected from the live ring, getLiveRing() would have error out.
+ if ( count( $this->weightByLocation ) == 1 ) {
+ return ( $limit > 0 ) ? [ $ring[0][self::KEY_LOCATION] ] : [];
+ }
+
// Locate the node index for this item's position on the hash ring
$itemIndex = $this->findNodeIndexForPosition( $this->getItemPosition( $item ), $ring );
$stat = $this->getFileStat( $params );
}
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
return $stat['xattr'];
} else {
return false;
* This is true for the request headers and the response headers. Integer-indexed
* method/URL entries will also be changed to use the corresponding string keys.
*
- * @param array $reqs Map of HTTP request arrays
+ * @param array[] $reqs Map of HTTP request arrays
* @param array $opts
* - connTimeout : connection timeout per request (seconds)
* - reqTimeout : post-connection timeout per request (seconds)
*
* @see MultiHttpClient::runMulti()
*
- * @param array $reqs Map of HTTP request arrays
+ * @param array[] $reqs Map of HTTP request arrays
* @param array $opts
* - connTimeout : connection timeout per request (seconds)
* - reqTimeout : post-connection timeout per request (seconds)
* - reqTimeout : default request timeout
* @return resource
* @throws Exception
+ * @suppress PhanTypeMismatchArgumentInternal
*/
protected function getCurlHandle( array &$req, array $opts = [] ) {
$ch = curl_init();
/**
* Normalize request information
*
- * @param array $reqs the requests to normalize
+ * @param array[] $reqs the requests to normalize
*/
private function normalizeRequests( array &$reqs ) {
foreach ( $reqs as &$req ) {
final protected function doLockByType( array $pathsByType ) {
$status = StatusValue::newGood();
- $pathsToLock = []; // (bucket => type => paths)
+ $pathsByTypeByBucket = []; // (bucket => type => paths)
// Get locks that need to be acquired (buckets => locks)...
foreach ( $pathsByType as $type => $paths ) {
foreach ( $paths as $path ) {
++$this->locksHeld[$path][$type];
} else {
$bucket = $this->getBucketFromPath( $path );
- $pathsToLock[$bucket][$type][] = $path;
+ $pathsByTypeByBucket[$bucket][$type][] = $path;
}
}
}
+ // Acquire locks in each bucket in bucket order to reduce contention. Any blocking
+ // mutexes during the acquisition step will not involve circular waiting on buckets.
+ ksort( $pathsByTypeByBucket );
+
$lockedPaths = []; // files locked in this attempt (type => paths)
// Attempt to acquire these locks...
- foreach ( $pathsToLock as $bucket => $pathsToLockByType ) {
+ foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) {
// Try to acquire the locks for this bucket
- $status->merge( $this->doLockingRequestBucket( $bucket, $pathsToLockByType ) );
+ $status->merge( $this->doLockingRequestBucket( $bucket, $bucketPathsByType ) );
if ( !$status->isOK() ) {
$status->merge( $this->doUnlockByType( $lockedPaths ) );
return $status;
}
// Record these locks as active
- foreach ( $pathsToLockByType as $type => $paths ) {
+ foreach ( $bucketPathsByType as $type => $paths ) {
foreach ( $paths as $path ) {
$this->locksHeld[$path][$type] = 1; // locked
// Keep track of what locks were made in this attempt
protected function doUnlockByType( array $pathsByType ) {
$status = StatusValue::newGood();
- $pathsToUnlock = []; // (bucket => type => paths)
+ $pathsByTypeByBucket = []; // (bucket => type => paths)
foreach ( $pathsByType as $type => $paths ) {
foreach ( $paths as $path ) {
if ( !isset( $this->locksHeld[$path][$type] ) ) {
if ( $this->locksHeld[$path][$type] <= 0 ) {
unset( $this->locksHeld[$path][$type] );
$bucket = $this->getBucketFromPath( $path );
- $pathsToUnlock[$bucket][$type][] = $path;
+ $pathsByTypeByBucket[$bucket][$type][] = $path;
}
if ( $this->locksHeld[$path] === [] ) {
unset( $this->locksHeld[$path] ); // no SH or EX locks left for key
// Remove these specific locks if possible, or at least release
// all locks once this process is currently not holding any locks.
- foreach ( $pathsToUnlock as $bucket => $pathsToUnlockByType ) {
- $status->merge( $this->doUnlockingRequestBucket( $bucket, $pathsToUnlockByType ) );
+ foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) {
+ $status->merge( $this->doUnlockingRequestBucket( $bucket, $bucketPathsByType ) );
}
if ( $this->locksHeld === [] ) {
$status->merge( $this->releaseAllLocks() );
}
/**
- * @param string $fname the filename
+ * @param string $xml
+ * @param bool $isFile
*/
private function validateFromInput( $xml, $isFile ) {
$reader = new XMLReader();
*
* @ingroup Cache
* @ingroup Redis
+ * @phan-file-suppress PhanTypeComparisonFromArray It's unclear whether exec() can return false
*/
class RedisBagOStuff extends MediumSpecificBagOStuff {
/** @var RedisConnectionPool */
* @ingroup Database
* @since 1.22
* @see Database
+ * @phan-file-suppress PhanParamSignatureMismatch resource vs mysqli_result
*/
class DatabaseMysqli extends DatabaseMysqlBase {
/**
* that field to. The data will be quoted by IDatabase::addQuotes().
* Values with integer keys form unquoted SET statements, which can be used for
* things like "field = field + 1" or similar computed values.
- * @param array $conds An array of conditions (WHERE). See
+ * @param array|string $conds An array of conditions (WHERE). See
* IDatabase::select() for the details of the format of condition
* arrays. Use '*' to update all rows.
* @param string $fname The function name of the caller (from __METHOD__),
* @param string $joinTable The other table.
* @param string $delVar The variable to join on, in the first table.
* @param string $joinVar The variable to join on, in the second table.
- * @param array $conds Condition array of field names mapped to variables,
+ * @param array|string $conds Condition array of field names mapped to variables,
* ANDed together in the WHERE clause
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
* @throws DBError If an error occurs, see IDatabase::query()
* @see https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html
*/
class MySQLMasterPos implements DBMasterPos {
- /** @var int One of (BINARY_LOG, GTID_MYSQL, GTID_MARIA) */
+ /** @var string One of (BINARY_LOG, GTID_MYSQL, GTID_MARIA) */
private $style;
/** @var string|null Base name of all Binary Log files */
private $binLog;
/** @var DatabaseDomain Local DB domain ID and default for selectDB() calls */
private $localDomain;
- /** @var Database[][][] Map of (connection category => server index => IDatabase[]) */
+ /**
+ * @var IDatabase[][][]|Database[][][] Map of (connection category => server index => IDatabase[])
+ */
private $conns;
/** @var array[] Map of (server index => server config array) */
private $tableAliases = [];
/** @var string[] Map of (index alias => index) */
private $indexAliases = [];
- /** @var array[] Map of (name => callable) */
+ /** @var callable[] Map of (name => callable) */
private $trxRecurringCallbacks = [];
/** @var bool[] Map of (domain => whether to use "temp tables only" mode) */
private $tempTablesOnlyMode = [];
*
* @since 1.26
* @param string $blob
- * @return array
+ * @return array|false
*/
public static function extractParams( $blob ) {
return unserialize( $blob );
/**
* @param File $image
- * @param array $metadata
+ * @param string $metadata
* @return bool|int
*/
public function isMetadataValid( $image, $metadata ) {
* Exif::getFilteredData() or BitmapMetadataHandler )
* @return array
* @since 1.23
+ * @suppress PhanTypeArraySuspiciousNullable
*/
public function makeFormattedData( $tags ) {
$resolutionunit = !isset( $tags['ResolutionUnit'] ) || $tags['ResolutionUnit'] == 2 ? 2 : 3;
* @param string $ext
* @param string $mime
* @param array|null $params
- * @return bool
+ * @return array
*/
public function getThumbType( $ext, $mime, $params = null ) {
global $wgTiffThumbnailType;
$this->numServerShards = count( $this->serverInfos );
} else {
// Default to using the main wiki's database servers
- $this->serverInfos = false;
+ $this->serverInfos = [];
$this->numServerShards = 1;
$this->attrMap[self::ATTR_SYNCWRITES] = self::QOS_SYNCWRITES_BE;
}
*/
public $mLatest = false;
- /** @var PreparedEdit Map of cache fields (text, parser output, ect) for a proposed/new edit */
+ /**
+ * @var PreparedEdit|false Map of cache fields (text, parser output, ect) for a proposed/new edit
+ */
public $mPreparedEdit = false;
/**
*
* @param int|bool $openingCount
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function breakSyntax( $openingCount = false ) {
if ( $this->open == "\n" ) {
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$accum = array_merge( [ $this->savedPrefix ], $this->parts[0]->out );
} else {
if ( $openingCount === false ) {
* @param string $sep
* @param int $flags
* @param string|PPNode $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return string
*/
public function implodeWithFlags( $sep, $flags /*, ... */ );
* Implode with no flags specified
* @param string $sep
* @param string|PPNode $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return string
*/
public function implode( $sep /*, ... */ );
* Makes an object that, when expand()ed, will be the same as one obtained
* with implode()
* @param string $sep
- * @param string|PPNode $args,...
+ * @param string|PPNode ...$args
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return PPNode
*/
- public function virtualImplode( $sep /*, ... */ );
+ public function virtualImplode( $sep /* ...$args */ );
/**
* Virtual implode with brackets
* @param string $start
* @param string $sep
* @param string $end
- * @param string|PPNode $args,...
+ * @param string|PPNode ...$args
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return PPNode
*/
- public function virtualBracketedImplode( $start, $sep, $end /*, ... */ );
+ public function virtualBracketedImplode( $start, $sep, $end /* ...$args */ );
/**
* Returns true if there are no arguments in this frame
* @param string $sep
* @param string|PPNode_DOM|DOMNode ...$args
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function virtualImplode( $sep, ...$args ) {
$out = [];
* @param string $end
* @param string|PPNode_DOM|DOMNode ...$args
* @return array
+ * @suppress PhanParamSignatureMismatch
*/
public function virtualBracketedImplode( $start, $sep, $end, ...$args ) {
$out = [ $start ];
*/
public function replaceExternalLinks( $text ) {
$bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
+ // @phan-suppress-next-line PhanTypeComparisonFromArray See phan issue #3161
if ( $bits === false ) {
throw new MWException( "PCRE needs to be compiled with "
. "--enable-unicode-properties in order for MediaWiki to function" );
*/
protected function getTimeZoneList( Language $language ) {
$identifiers = DateTimeZone::listIdentifiers();
+ // @phan-suppress-next-line PhanTypeComparisonFromArray See phan issue #3162
if ( $identifiers === false ) {
return [];
}
<?php
class ProfilerExcimer extends Profiler {
+ /** @var ExcimerProfiler */
private $cpuProf;
+ /** @var ExcimerProfiler */
private $realProf;
private $period;
*/
private $context;
+ /** @var int|array */
protected $modules = self::INHERIT_VALUE;
protected $language = self::INHERIT_VALUE;
protected $direction = self::INHERIT_VALUE;
if ( $this->modules === self::INHERIT_VALUE ) {
return $this->context->getModules();
}
- // @phan-suppress-next-line PhanTypeMismatchReturn
+
return $this->modules;
}
protected $direction;
protected $hash;
protected $userObj;
+ /** @var ResourceLoaderImage|false */
protected $imageObj;
/**
* @param string|string[]|MessageSpecifier $key Message key, or array of keys,
* or a MessageSpecifier.
* @param mixed $args,...
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function msg( $key ) {
// clear get_last_error without actually raising an error
// from https://www.php.net/manual/en/function.error-get-last.php#113518
- // TODO replace with clear_last_error when requirements are bumped to PHP7
+ // TODO replace with error_clear_last after dropping HHVM
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
set_error_handler( function () {
}, 0 );
AtEase::suppressWarnings();
*
* @since 1.21
*
- * @var array[]
+ * @var array[]|false
*/
protected $localIds = [];
*
* @param string $name Message name
* @param mixed $params,... Message params
+ * @suppress PhanCommentParamWithoutRealParam HHVM bug T228695#5450847
* @return Message
*/
public function getMsg( $name /* ... */ ) {
/**
* Process the form on POST submission.
* @param array $data
- * @param HTMLForm $form
+ * @param HTMLForm|null $form
+ * @suppress PhanCommentParamWithoutRealParam Many implementations don't have $form
* @return bool|string|array|Status As documented for HTMLForm::trySubmit.
*/
- abstract public function onSubmit( array $data /* $form = null */ );
+ abstract public function onSubmit( array $data /* HTMLForm $form = null */ );
/**
* Do something exciting on successful processing of the form, most likely to show a
'restrictions' => $data['restrictions'],
'grants' => array_merge(
MWGrants::getHiddenGrants(),
+ // @phan-suppress-next-next-line PhanTypeMismatchArgumentInternal See phan issue #3163,
+ // it's probably failing to infer the type of $data['grants']
preg_replace( '/^grant-/', '', $data['grants'] )
)
] );
];
foreach ( $changeGroups as $messageKey => $changeGroup ) {
+ // @phan-suppress-next-line PhanTypeComparisonFromArray
if ( $changeGroup === true ) {
// For grep: listgrouprights-addgroup-all, listgrouprights-removegroup-all,
// listgrouprights-addgroup-self-all, listgrouprights-removegroup-self-all
private $mOriginalLogCallback = null;
private $mOriginalPageOutCallback = null;
private $mLogItemCount = 0;
+ private $mPageCount;
+ private $mIsUpload;
+ private $mInterwiki;
/**
* @param WikiImporter $importer
return $headers;
}
+ /**
+ * @param string $name
+ * @param string $value
+ * @return string
+ * @suppress PhanTypeArraySuspiciousNullable
+ */
function formatValue( $name, $value ) {
static $msg = null;
if ( $msg === null ) {
* Check a block of CSS or CSS fragment for anything that looks like
* it is bringing in remote code.
* @param string $value a string of CSS
- * @param bool $propOnly only check css properties (start regex with :)
* @return bool true if the CSS contains an illegal string, false if otherwise
*/
private static function checkCssFragment( $value ) {
/**
* Check if a given user has permission to use this functionality.
* @param User $user
- * @param bool $displayPassword If set, also check whether the user is allowed to reset the
- * password of another user and see the temporary password.
* @since 1.29 Second argument for displayPassword removed.
* @return StatusValue
*/
'mActorId',
];
- /**
- * @var string[]
- * @var string[] Cached results of getAllRights()
- */
- protected static $mAllRights = false;
-
/** Cache variables */
// @{
/** @var int */
$joinConds
);
- return $res === false ? [] : $res;
+ return $res;
}
}
protected $startToken;
/**
- * @var array List of tokens that are members of the current expect sequence
+ * @var array[]|string[] List of tokens that are members of the current expect sequence
*/
protected $tokens;
/**
* Accepts the next token in an expect sequence
*
- * @param array $token
+ * @param array|string $token
*/
protected function tryEndExpect( $token ) {
switch ( $this->startToken[0] ) {
* @param string $profile The currently selected profile
* @param string $term The user provided search terms
* @return string HTML
+ * @suppress PhanTypeArraySuspiciousNullable
*/
protected function profileTabsHtml( $profile, $term ) {
$bareterm = $this->startsWithImage( $term )
public $mVariants, $mCode, $mLoaded = false;
public $mMagicExtensions = [];
- private $mHtmlCode = null, $mParentLanguage = false;
+ private $mHtmlCode = null;
+ /** @var Language|false */
+ private $mParentLanguage = false;
public $dateFormatStrings = [];
public $mExtendedSpecialPageAliases;
}
function __construct() {
+ // @phan-suppress-next-line PhanTypeMismatchProperty
$this->mConverter = new FakeConverter( $this );
// Set the code to the name of the descendant
if ( static::class === 'Language' ) {
# The above mixing may leave namespaces out of canonical order.
# Re-order by namespace ID number...
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
ksort( $this->namespaceNames );
Hooks::run( 'LanguageGetNamespaces', [ &$this->namespaceNames ] );
$fallbackChain = array_reverse( $fallbackChain );
foreach ( $fallbackChain as $code ) {
if ( isset( $newWords[$code] ) ) {
+ // @phan-suppress-next-line PhanTypeMismatchProperty
$this->mMagicExtensions = $newWords[$code] + $this->mMagicExtensions;
}
}
public $mTablesLoaded = false;
/**
- * @var ReplacementArray[]
- * @phan-var array<string,ReplacementArray>
+ * @var ReplacementArray[]|bool[]
*/
public $mTables;
}
$this->mTablesLoaded = true;
- $this->mTables = false;
+ $this->mTables = null;
$cache = ObjectCache::getInstance( $wgLanguageConverterCacheType );
$cacheKey = $cache->makeKey( 'conversiontables', $this->mMainLanguageCode );
if ( $fromCache ) {
$this->fatalError( "Error: Closures cannot be converted to JSON. " .
"Please move your extension function somewhere else."
);
- }
- // check if $func exists in the global scope
- if ( function_exists( $func ) ) {
- // @phan-suppress-next-next-line PhanTypeSuspiciousStringExpression
+ } elseif ( function_exists( $func ) ) {
+ // check if $func exists in the global scope
$this->fatalError( "Error: Global functions cannot be converted to JSON. " .
"Please move your extension function ($func) into a class."
);
$this->fatalError( "Error: Closures cannot be converted to JSON. " .
"Please move the handler for $hookName somewhere else."
);
- }
- // Check if $func exists in the global scope
- if ( function_exists( $func ) ) {
+ } elseif ( function_exists( $func ) ) {
+ // Check if $func exists in the global scope
$this->fatalError( "Error: Global functions cannot be converted to JSON. " .
"Please move the handler for $hookName inside a class."
);
// backends in FileBackendMultiWrite (since they get writes second, they have
// higher timestamps). However, when copying the other way, this hits loads of
// false positives (possibly 100%) and wastes a bunch of time on GETs/PUTs.
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
$same = ( $srcStat['mtime'] <= $dstStat['mtime'] );
} else {
// This is the slowest method which does many per-file HEADs (unless an object
/**
* A resource pointing to a sitemap file
*
- * @var resource
+ * @var resource|false
*/
public $file;
public $uploads = false;
protected $uploadCount = 0;
public $imageBasePath = false;
+ /** @var array|false */
public $nsFilter = false;
function __construct() {
protected $bufferSize = 524288; // In bytes. Maximum size to read from the stub in on go.
- protected $php = "php";
+ /** @var array */
+ protected $php = [];
protected $spawn = false;
/**
protected $spawnProc = false;
/**
- * @var bool|resource
+ * @var resource
*/
- protected $spawnWrite = false;
+ protected $spawnWrite;
/**
- * @var bool|resource
+ * @var resource
*/
- protected $spawnRead = false;
+ protected $spawnRead;
/**
* @var bool|resource
/**
* @throws MWException Failure to parse XML input
- * @param string $input
+ * @param resource $input
* @return bool
*/
function readDump( $input ) {
if ( $this->spawnRead ) {
fclose( $this->spawnRead );
}
- $this->spawnRead = false;
+ $this->spawnRead = null;
if ( $this->spawnWrite ) {
fclose( $this->spawnWrite );
}
- $this->spawnWrite = false;
+ $this->spawnWrite = null;
if ( $this->spawnErr ) {
fclose( $this->spawnErr );
}
/**
* @param MediaWiki\Revision\RevisionStore $revStore
- * @param string $emptySha1
* @return int
*/
protected function doSha1LegacyUpdates( $revStore ) {
/** @var RecompressTracked */
public $parent;
public $blobClass;
- /** @var ConcatenatedGzipHistoryBlob */
+ /** @var ConcatenatedGzipHistoryBlob|false */
public $cgz;
public $referrers;
}
}
+ public function testHashRingSingleLocation() {
+ // SHA-1 based and weighted
+ $ring = new HashRing( [ 's1' => 1 ], 'sha1' );
+
+ $this->assertEquals(
+ [ 's1' => 1 ],
+ $ring->getLocationWeights(),
+ 'Normalized location weights'
+ );
+
+ for ( $i = 0; $i < 5; $i++ ) {
+ $this->assertEquals(
+ 's1',
+ $ring->getLocation( "hello$i" ),
+ 'Items placed at proper locations'
+ );
+ $this->assertEquals(
+ [ 's1' ],
+ $ring->getLocations( "hello$i", 2 ),
+ 'Items placed at proper locations'
+ );
+ }
+
+ $this->assertEquals( [], $ring->getLocations( "helloX", 0 ), "Limit of 0" );
+ }
+
public function testHashRingMapping() {
// SHA-1 based and weighted
$ring = new HashRing(