Tools 是非官方社区Wiki。社区文档正在编写中,欢迎参与。 Wiki编辑答疑群:717421103
版本250722.2
全站通知:

帮助:解析函数/ifexist

来自WIKI实验室WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

ifexist是一个解析函数。帮助:解析函数页列出了所有解析函数的说明。

ifexist

【高开销】条件分支函数,条件是指定页面/文件是否存在。出自扩展 ParserFunctions

检查目标页面标题是否存在并返回对应结果值,支持检测文件是否存在。不支持跨wiki链接。

语法

{{#ifexist: 页面标题 | 存在时的值 | 不存在时的值 }}

  • 页面标题:要检查的页面标题
  • 存在时的值:当页面存在时输出的内容
  • 不存在时的值:当页面不存在时输出的内容

使用此函数的页面被视为链接到了要检查的页面,计入对应页面的链入页面


此函数被标记为“高开销”。在bwiki,每个页面最多能使用100次高开销函数,超出后始终返回“不存在时的值”,并添加页面到分类:有过多高开销解析器函数调用的页面。 不过,如果检查目标是特殊页面、跨wiki链接或命中查询缓存,则不增加高开销计数(即,检查特殊页面存在性不是高开销的,检查一百次同一页面被视为使用一次高开销函数)。


要了解页面中高开销函数的使用情况,可以在编辑预览时,查看底部“解析器分析数据”表格。


超限制时的替代方式:部分情况可用CSS选择器如a.newa:not(.new)模拟部分效果。 如果一定需要同时判断大量页面是否存在,文件可以通过函数filepath结果判断。页面可以通过判断#contributors替代,它们虽然实际开销不低,但没有被标记为“高开销”,没有单页使用次数限制。

示例

  • 普通页面:{{#ifexist: Help:解析函数 | exists | doesn't exist }} → exists
  • 不存在页面:{{#ifexist: 帮助:如何PUA辰纱 | exists | doesn't exist }} → doesn't exist
  • 特殊页面:{{#ifexist: 特殊:监视列表 | exists | doesn't exist }} → exists
  • 检查文件:{{#ifexist: 文件:Test.png | exists | doesn't exist }} → exists
  • 系统消息:{{#ifexist: MediaWiki:Copyright | exists | doesn't exist }} → doesn't exist


底层代码

来自MediaWiki及其扩展的源代码,运行在服务端。此处仅供快速查阅,便于更充分的挖掘其“特性”。

/** mediawiki-extensions-ParserFunctions-REL1_37\includes\ParserFunctions.php
 * {{#ifexist: page title | value if exists | value if doesn't exist }}
 *
 * @link https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions##ifexist
 *
 * @param Parser $parser
 * @param PPFrame $frame
 * @param array $args
 * @return string
 */
public static function ifexist( Parser $parser, PPFrame $frame, array $args ) {
	$title = isset( $args[0] ) ? trim( $frame->expand( $args[0] ) ) : '';
	$then = $args[1] ?? null;
	$else = $args[2] ?? null;

	$result = self::ifexistInternal( $parser, $frame, $title, $then, $else );
	if ( $result === null ) {
		return '';
	} else {
		return trim( $frame->expand( $result ) );
	}
}


/** mediawiki-extensions-ParserFunctions-REL1_37\includes\ParserFunctions.php
 * @param Parser $parser
 * @param PPFrame $frame
 * @param string $titletext
 * @param string $then
 * @param string $else
 *
 * @return string
 */
private static function ifexistInternal(
	Parser $parser, PPFrame $frame, $titletext = '', $then = '', $else = ''
) {
	$title = Title::newFromText( $titletext );
	self::getLanguageConverter( $parser->getContentLanguage() )
		->findVariantLink( $titletext, $title, true );
	if ( $title ) {
		if ( $title->getNamespace() === NS_MEDIA ) {
			/* If namespace is specified as NS_MEDIA, then we want to
				* check the physical file, not the "description" page.
				*/
			if ( !$parser->incrementExpensiveFunctionCount() ) {
				return $else;
			}
			$file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title );
			if ( !$file ) {
				$parser->getOutput()->addImage(
					$title->getDBKey(), false, false );
				return $else;
			}
			$parser->getOutput()->addImage(
				$file->getName(), $file->getTimestamp(), $file->getSha1() );
			return $file->exists() ? $then : $else;
		} elseif ( $title->isSpecialPage() ) {
			/* Don't bother with the count for special pages,
				* since their existence can be checked without
				* accessing the database.
				*/
			return MediaWikiServices::getInstance()->getSpecialPageFactory()
				->exists( $title->getDBkey() ) ? $then : $else;
		} elseif ( $title->isExternal() ) {
			/* Can't check the existence of pages on other sites,
				* so just return $else.  Makes a sort of sense, since
				* they don't exist _locally_.
				*/
			return $else;
		} else {
			$pdbk = $title->getPrefixedDBkey();
			$lc = MediaWikiServices::getInstance()->getLinkCache();
			$id = $lc->getGoodLinkID( $pdbk );
			if ( $id !== 0 ) {
				$parser->getOutput()->addLink( $title, $id );
				return $then;
			} elseif ( $lc->isBadLink( $pdbk ) ) {
				$parser->getOutput()->addLink( $title, 0 );
				return $else;
			}
			if ( !$parser->incrementExpensiveFunctionCount() ) {
				return $else;
			}
			$id = $title->getArticleID();
			$parser->getOutput()->addLink( $title, $id );

			// bug 70495: don't just check whether the ID != 0
			if ( $title->exists() ) {
				return $then;
			}
		}
	}
	return $else;
}
代码逻辑:
  • 优先检查缓存,减少数据库查询
  • 特殊页面直接通过工厂类检查存在性
  • 媒体文件检查跳过描述页直接查询文件存储库
  • 每次有效检查会累加高开销函数计数器
  • 存在性结果会记录到元数据链入页面中

实际用例

一些Wiki使用了相关特性,如下所示这个静态列表可能在下列页面更改后过时仅供批判性参考
碧蓝航线 - blhx

原神 - ys

战双帕弥什 - zspms

明日方舟 - arknights

恋与深空 - lysk

崩坏:星穹铁道 - sr

代号鸢 - yuan

赛马娘 - umamusume

坎特伯雷公主与骑士唤醒冠军之剑的奇幻冒险 - gt

黑神话:悟空 - wukong

WIKI实验室 - tools

东方归言录 - touhoulostword

白荆回廊 - bjhl

女神转生 - persona

赛尔计划 - seerplan

幻塔 - ht

绝区零 - zzz

重返未来:1999 - reverse1999

偶像大师灰姑娘女孩 - imascg

无期迷途 - wqmt

奇迹暖暖 - qjnn

赛尔号 - seer

地下城堡3 - dxcb3

红警3 - redalert3

孙美琪疑案 - sunmeiqi

鸣潮 - wutheringwaves

交错战线 - crosscore

千年之旅 - elf

生死狙击2 - ssjj2

戴森球计划 - dsp

梦幻模拟战 - langrisser

StardewValley星露谷物语 - stardewvalley

赛尔号星球大战 - seerwar

方舟指令 - fzzl

少前2:追放 - gf2

深空之眼 - dhmmr

克鲁赛德战记 - cq

冒险岛 - maplestory