Manual:解析器函数

From mediawiki.org
This page is a translated version of the page Manual:Parser functions and the translation is 58% complete.
Outdated translations are marked like this.
MediaWiki extensions

解析器函数(Parser function),加入于MediaWiki 1.7,是一种与解析器紧密集成的扩展。 短语“解析器函数”不应与Extension:解析器函數 混淆,后者是简单解析器函数的集合。 (请参阅Help:Extension:解析器函數 。)

描述

虽然标签扩展需要获取未处理的文本并将超文本标记语言返回给浏览器,但解析器函数可以与页面中的其他wiki元素“交互”。例如,解析器函数的输出可以用作模板参数或构造链接

解析器函数的典型语法是:

{{ #functionname: param1 | param2 | param3 }}

有关更多信息,请参阅文档Parser::setFunctionHook ( $id, $callback, $flags = 0 )。本文档说明:

回調函數應具有以下形式:
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
或者 SFH_OBJECT_ARGS:
function myParserFunction( $parser, $frame, $args ) { ... }

The first variant of the call passes all arguments as plain text. The second passes all arguments as an array of PPNode s, except for the first ($args[0]), which is currently text, though this may change in the future. These represent the unexpanded wikitext. The $frame parameter can be used to expand these arguments as needed. This is commonly used for conditional processing so that only the "true" case is evaluated with an if- or switch-like parser function. The frame object can also climb up the document tree to get information about the caller and has functions to determine and manage call depth, time-to-live, and whether the result of the parser function is volatile.

創建解析器函數比創建新標記稍微複雜一些,因為函數名稱必須是魔術字,這是一個支持別名和本地化的關鍵字。

简单例子

下面是一個創建解析器函數的擴展示例。

註冊分別進入extension.jsonsrc/ExampleExtensionHooks.php

{
	"name": "ExampleExtension",
	"author": "Me",
	"version": "1.0.0",
	"url": "https://www.mediawiki.org/wiki/Extension:ExampleExtension",
	"descriptionmsg": "exampleextension-desc",
	"license-name": "GPL-2.0-or-later",
	"type": "parserhook",
	"MessagesDirs": {
		"ExampleExtension": [
			"i18n"
		]
	},
	"AutoloadClasses": {
		"ExampleExtensionHooks": "src/ExampleExtensionHooks.php"
	},
	"ExtensionMessagesFiles": {
		"ExampleExtensionMagic": "ExampleExtension.i18n.php"
	},
	"Hooks": {
		"ParserFirstCallInit": "ExampleExtensionHooks::onParserFirstCallInit"
	},
	"manifest_version": 1
}
<?php
class ExampleExtensionHooks {
   // 使用解析器註冊任何渲染回調
   public static function onParserFirstCallInit( Parser $parser ) {

      // 創建一個函數鉤子,將“示例”魔術詞與renderExample()相關聯
      $parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
   }

   // 渲染{{#example:}}的輸出。
   public static function renderExample( Parser $parser, $param1 = '', $param2 = '', $param3 = '' ) {

      // 輸入參數是擴展了模板的wikitext,。
      // 輸出也應該是wikitext。
      $output = "param1 is $param1 and param2 is $param2 and param3 is $param3";

      return $output;
   }
}

擴展目錄(不在src/子目錄中)的另一個文件ExampleExtension.i18n.php應該包含:

<?php
/**
 * @license GPL-2.0-or-later
 * @author Your Name (YourUserName)
 */

$magicWords = [];

/** English
 * @author Your Name (YourUserName)
 */
$magicWords['en'] = [
   'example' => [ 0, 'example' ],
];

啟用此擴展程序後,

  • {{#example: hello | hi | hey}}

生产:

  • param1 is hello and param2 is hi and param3 is hey
這個magicWords數組不是可選的。 如果省略,解析器函數將無法工作; {{#example: hello | hi}}將被渲染,就像沒有安裝擴展一樣。 If only the language-specific array is initialized and not the magicWords array itself, this can cause localization errors as translations from other extensions leak into yours. 您可以在 PHP 中内联关联魔术词,而不是通过 i18n 文件。 这在 LocalSettings.php 中定义钩子时很有用
MediaWiki\MediaWikiServices::getInstance()->getContentLanguage()->mMagicExtensions['wikicodeToHtml'] = ['MAG_CUSTOM', 'custom'];

Within LocalSettings.php

Magic words and their handling parser functions can be defined entirely in LocalSettings.php.

$wgHooks['ParserFirstCallInit'][] = function ( Parser $parser ) 
{
	MediaWiki\MediaWikiServices::getInstance()->getContentLanguage()->mMagicExtensions['wikicodeToHtml'] = ['wikicodeToHtml', 'wikicodeToHtml'];

	$parser->setFunctionHook( 'wikicodeToHtml', 'wikicodeToHtml' );
};
 
function wikicodeToHtml( Parser $parser, $code = '' ) 
{
	$title = $parser->getTitle();
	$options = $parser->Options();
	$options->enableLimitReport(false);
	$parser = $parser->getFreshParser();
	return [$parser->parse($code, $title, $options)->getText(), 'isHTML' => true];
}

较长的函数

對於更長的函數,您可能希望將鉤子函數拆分為_body.php或.hooks.php文件,並使它們成為類的靜態函數。 然後你可以用$wgAutoloadClasses 加載類並在鉤子中調用靜態函數; 例如。:

把它放在你的extension.json文件中:

"Hooks": {
	"ParserFirstCallInit": "ExampleExtensionHooks::onParserFirstCallInit"
},
"AutoloadClasses": {
	"ExampleExtensionHooks": "src/ExampleExtensionHooks.php"
}

然後把它放在你的src/ExampleExtensionHooks.php文件中:

class ExampleExtensionHooks {
      public static function onParserFirstCallInit( Parser $parser ) {
           $parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
      }
}

解析器接口

控制輸出的解析

要使解析器函數返回的wiki文本得到完全解析(包括擴展模板),請在返回時將noparse選項設置為false:

return [ $output, 'noparse' => false ];

至少在某些情況下,有時是1.12版本左右,似乎noparse的默認值從false變為true。

相反,要使您的解析器函數返回仍未解析的超文本標記語言,而不是返回wiki文本,請使用以下命令:

return [ $output, 'noparse' => true, 'isHTML' => true ];

命名

默认情况下,MW 会在每个解析器函数的名称中添加一个哈希字符(数字符号,“#”)。 要抑制该添加(并获得没有“#”前缀的解析器函数),请在 setFunctionHook 的可选标志参数中包含 SFH_NO_HASH 常量,如 below 所述。

在選擇沒有哈希前綴的名稱時,請注意,不再可能刪除名稱以該函數名稱開頭後跟冒號的頁面。 特別是,避免使用等於命名空間名稱的函數名稱。 在啟用interwiki transclusion [1] 的情況下,還要避免使用等於interwiki前綴的函數名稱。

setFunctionHook掛鉤

有關解析器接口的更多詳細信息,請參閱includes/Parser.php.中setFunctionHook的文檔。 這是這些評論的副本(可能是註明日期):

function setFunctionHook( $id, $callback, $flags = 0 )

参数:

  • string $id - 魔術字標識符
  • mixed $callback - 要使用的回調函數(和對象)
  • integer $flags - 可選,將其設置為SFH_NO_HASH常量,以調用不帶“#”的函數。

Set it to SFH_OBJECT_ARGS (2) to pass a PPFrame object and array of arguments instead of a series of function arguments, for which see above. Defaults to 0 (no flags).

返回值:此名稱的舊回調函數(如果有)

創建一個函數,例如{{#sum:1|2|3}}。 回調函數應具有以下形式:

function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }

回調可以返回函數的文本結果,也可以返回帶有文本的數組 在元素0中,以及其他元素中的許多標誌。 標誌的名稱是 在鍵中指定。 有效標誌是:

Name Type Default Description
found Boolean true 返回的文本有效,停止處理模板。 默認情況下啟用此選項。
text ? ? The text to return from the function. If isChildObj or isLocalObj are specified, this should be a DOM node instead.
noparse Boolean true 不應剝離不安全的HTML標籤等。
isHTML Boolean ? 返回的文本是HTML,裝備它反對wikitext轉換 But see discussion
nowiki Boolean usually false 應該轉義返回值中的Wiki標記
isChildObj Boolean ? true if the text is a DOM node needing expansion in a child frame.
isLocalObj Boolean ? true if he text is a DOM node needing expansion in the current frame. The default value depends on other values and outcomes.
preprocessFlags ? false Optional PPFrame flags to use when parsing the returned text. This only applies when noparse is false.
title ? false The Title object where the text came from.
forceRawInterwiki Boolean ? true if interwiki transclusion must be forced to be done in raw mode and not rendered.


Expensive parser functions

Some parser functions represent a significant use of a wiki's resources and should be marked as "expensive". The number of expensive parser functions on any given page is limited by the $wgExpensiveParserFunctionLimit setting. What counts as expensive is left up to the function itself, but typically, anything that is likely to cause a delay that extends beyond simple processing of data should be considered. This includes things like database reads and writes, launching a shell script synchronously, or file manipulation. On the other hand, not all such functions should necessarily be tagged. Semantic MediaWiki, for example, only marks a percentage of its database reads as expensive. This is due to the fact that on certain data-intensive pages, it could easily overflow the normal expensive parser function limits. In cases like this, the potential for noticeably slower performance that doesn't get flagged as expensive is a trade-off to having the functionality that SMW offers.

To mark your parser function as expensive, from within the body of the function's code, use $result = $parser->incrementExpensiveFunctionCount();. The return value will be false if the expensive function limit has been reached or exceeded.

命名參數

解析器函數不像模板和標記擴展那樣支持命名參數,但偶爾會偽造它。 用戶通常習慣使用豎線(|)來分隔參數,因此能夠在解析器函數上下文中做到這一點也很好。 以下是如何完成此操作的簡單示例:

function ExampleExtensionRenderParserFunction( &$parser ) {
	// Suppose the user invoked the parser function like so:
	// {{#myparserfunction: foo=bar | apple=orange | banana }}

	$options = extractOptions( array_slice( func_get_args(), 1 ) );

	// Now you've got an array that looks like this:
	// [foo] => 'bar'
	// [apple] => 'orange'
	// [banana] => true
	// Continue writing your code...
}

/**
 * Converts an array of values in form [0] => "name=value"
 * into a real associative array in form [name] => value
 * If no = is provided, true is assumed like this: [name] => true
 *
 * @param array string $options
 * @return array $results
 */
function extractOptions( array $options ) {
	$results = [];
	foreach ( $options as $option ) {
		$pair = array_map( 'trim', explode( '=', $option, 2 ) );
		if ( count( $pair ) === 2 ) {
			$results[ $pair[0] ] = $pair[1];
		}
		if ( count( $pair ) === 1 ) {
			$results[ $pair[0] ] = true;
		}
	}
	return $results;
}

参见

General and related guides:

Code:

Examples: