Руководство:Функции парсера
Функции парсера, добавленные в MediaWiki 1.7, представляют собой тип расширения, тесно интегрированного с парсером. Фразу "функция парсера" не следует путать с Расширение:Функции парсера , которая представляет собой набор простых функций парсера. (Смотрите Справка:Расширение:Функции парсера для этого.)
Описание
В то время как теги расширений обрабатывают необработанный текст и возвращают HTML в браузер, функции парсера могут 'взаимодействовать' с другими вики-элементами на странице. Например, вывод функций парсера может использоваться как шаблонный параметр или в конструкторе ссылок.
Типичный синтаксис парсера функции:
{{ #functionname: param1 | param2 | param3 }}
Для получения дополнительной информации см. Документацию по Parser::setFunctionHook ( $id, $callback, $flags = 0 )
. В этой документации указано:
- Функция обратного вызова должна иметь вид:
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
- Или с
SFH_OBJECT_ARGS
:function myParserFunction( $parser, $frame, $args ) { ... }
Первый вариант вызова передает все аргументы в виде обычного текста.
Второй передает все аргументы в виде массива из PPNode , за исключением первого ($args[0]
), который в настоящее время является текстом, хотя это может измениться в будущем.
Они представляют собой нерасширенный викитекст.
Параметр $frame
можно использовать для расширения этих аргументов по мере необходимости.
Это обычно используется для условной обработки, так что только "true" случай оценивается с помощью функции парсера, похожей на if или switch.
Объект фрейма также может подняться вверх по дереву документа, чтобы получить информацию о вызывающем объекте, и имеет функции для определения и управления глубиной вызова, временем жизни и изменчивостью результата функции синтаксического анализатора.
Создание функции синтаксического анализатора немного сложнее, чем создание нового тега, поскольку имя функции должно быть magic word, ключевым словом, поддерживающим псевдонимы и локализацию.
Простой пример
Ниже приведен пример расширения, которое создает функция парсера.
Запись переходит в extension.json, а код-в src/ExampleExtensionHooks.php соответственно:
Standard: | Using the HookHandler interface: |
---|---|
extension.json | |
{
"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
}
|
{
"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": "onParserFirstCallInit"
},
"HookHandlers": {
"ExampleExtensionHooks": {
"class": "MediaWiki\\Extension\\ExampleExtension\\Hooks"
}
},
"manifest_version": 1
}
|
ExampleExtensionHooks.php | |
<?php
class ExampleExtensionHooks {
// Запишите обратные вызовы рендеринга с помощью парсера
public static function onParserFirstCallInit( Parser $parser ) {
// Создайте функциональный крючок, связывающий волшебное слово "example" с renderExample()
$parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
}
// Визуализируйте выходные данные {{#example:}}.
public static function renderExample( Parser $parser, $param1 = '', $param2 = '', $param3 = '' ) {
// Входные параметры - викитекст с развернутыми шаблонами.
// Вывод тоже должен быть с викитекстом.
$output = "param1 is $param1 and param2 is $param2 and param3 is $param3";
return $output;
}
}
|
<?php
class ExampleExtensionHooks implements ParserFirstCallInitHook {
// Register any render callbacks with the parser
public function onParserFirstCallInit( $parser ) {
// Create a function hook associating the <code>example</code> magic word with renderExample()
$parser->setFunctionHook( 'example', [ $this, 'renderExample' ] );
}
// Render the output of {{#example:}}.
public function renderExample( $parser, $param1 = '', $param2 = '', $param3 = '' ) {
// The input parameters are wikitext with templates expanded.
// The output should be wikitext too.
$output = "param1 is $param1 and param2 is $param2 and param3 is $param3";
return $output;
}
}
|
Другой файл, ExampleExtension.i18n.php, в каталоге расширений (Не в подкаталоге src/) должен содержать:
<?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 это hello и param2 это hi и param3 это hey
LocalSettings.php
.
MediaWiki\MediaWikiServices::getInstance()->getContentLanguage()->mMagicExtensions['wikicodeToHtml'] = ['MAG_CUSTOM', 'custom'];
В пределах LocalSettings.php
Волшебные слова и функции парсера для их обработки могут быть полностью определены в 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' ] );
}
}
Интерфейс парсера
Контролирование вывода парсера
Чтобы викитекст, возвращаемые функцией парсер быть полностью разбираемый (в том числе расширение шаблонов), установите параметр noparse
, false при возвращении:
return [ $output, 'noparse' => false ];
Кажется, значение по умолчанию для noparse
изменилось с false на true, по крайней мере, в некоторых ситуациях, примерно в версии 1.12.
И наоборот, чтобы ваш парсер функция возвращает HTML, который остается непроанализированным, а не обратно викитекст, используйте это:
return [ $output, 'noparse' => true, 'isHTML' => true ];
Именование
По умолчанию, MW добавляет хэш-символа (знака, "#") перед названием каждой функции парсера. Чтобы подавить это дополнение (и получить синтаксический анализатор функционирует без "#" префикс), включать "SFH_NO_HASH" константа в необязательные флаги аргумент setFunctionHook, как описано ниже.
При выборе имени без хэш-префикса обратите внимание, что трансклюзия страницы с именем, начинающимся с этого имени функции, за которым следует двоеточие, более невозможна. В частности, избегайте имен функций, равных имени пространства имен. В том случае, если interwiki transclusion [1] включен, также избегайте имен функций, равных префиксу interwiki.
Хук setFunctionHook
Дополнительные сведения об интерфейсе синтаксического анализатора смотрите в документации по setFunctionHook в разделе includes/Parser.РНР. Вот (возможно, датированная) копия этих комментариев:
функция setFunctionHook( $id, $callback, $flags = 0 )
Параметры:
- строка $id - ID волшебного слова
- смешанный $callback - Функция обратного вызова (и объект) для использования
- целое число $flags — Необязательно, установите константу SFH_NO_HASH для вызова функции без "#".
- SFH_NO_HASH (1) constant if you call the function without
#
. - SFH_OBJECT_ARGS (2) if you pass a PPFrame object and array of arguments instead of a series of function arguments, for which see above.
- Defaults to 0 (no flags).
- SFH_NO_HASH (1) constant if you call the function without
Возвращаемое значение: Старая функция обратного вызова для этого имени, если есть
Создайте функцию, например, {{#sum:1|2|3}}
. Функция обратного вызова должна иметь вид:
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
Обратный вызов может либо возвращать текстовый результат функции, либо массив с текстом в элементе 0 и рядом флагов в других элементах. Имена флагов указаны в ключах. Допустимые флаги:
Name | Type | Default | Description |
---|---|---|---|
found | Boolean | true
|
true , если возвращенный текст действителен и обработка шаблона должна быть остановлена.
|
text | ? | ? | Текст, возвращаемый функцией. Если указаны isChildObj или isLocalObj, это должен быть узел DOM. |
noparse | Boolean | true
|
true , если текст не должен быть предварительно обработан в DOM-дереве, например, небезопасные HTML-теги не должны удаляться и т.д.
|
isHTML | Boolean | ? | true , если возвращаемый текст является HTML и должен быть защищен от преобразования викитекста. Но см. обсуждение
|
nowiki | Boolean | usually false
|
true , если вики-разметка в возвращаемом значении (тексте) должна быть экранирована.
|
isChildObj | Boolean | ? | true , если текст является DOM-узлом, нуждающимся в расширении в дочернем фрейме.
|
isLocalObj | Boolean | ? | true , если текст является DOM-узлом, нуждающимся в расширении в текущем фрейме. Значение по умолчанию зависит от других значений и результатов.
|
preprocessFlags | ? | false
|
Необязательные флаги PPFrame для использования при парсинге возвращаемого текста. Это применимо только тогда, когда noparse равен false .
|
title | ? | false
|
Объект Title , откуда был взят текст. |
forceRawInterwiki | Boolean | ? | true , если интервики трансклюзия должна быть принудительно выполнена в необработанном режиме, а не отрисована.
|
Затратные функции парсера
Некоторые функции парсера требуют значительного использования ресурсов вики и должны быть помечены как "затратные". Количество затратных функций парсера на любой данной странице ограничено настройкой $wgExpensiveParserFunctionLimit . Что считается затратным, остается на усмотрение самой функции, но, как правило, следует учитывать все, что может вызвать задержку, выходящую за рамки простой обработки данных. Это включает в себя такие вещи, как чтение и запись базы данных, синхронный запуск скриптов оболочки или манипулирование файлами. С другой стороны, не все такие функции обязательно должны быть помечены. Semantic MediaWiki, например, помечает как затратные только процент чтений своей базы данных. Это связано с тем, что на некоторых страницах с интенсивным использованием данных он может легко выйти за пределы обычных затратных ограничений функции парсера. В подобных случаях потенциальное снижение производительности, которое не будет помечено как затратное, является компромиссом с функциональностью, предлагаемой SMW.
Чтобы пометить вашу функцию парсера как ресурсоёмкую, в коде тела функции используйте $result = $parser->incrementExpensiveFunctionCount();
.
Возвращаемое значение будет false
, если лимит затратной функции достигнут или превышен.
Параметры
Функции синтаксического анализатора не поддерживают именованные параметры, как это делают шаблоны и расширения тегов, но иногда полезно подделать их. Пользователи часто привыкли использовать вертикальные полосы ( | ) для разделения аргументов, поэтому приятно иметь возможность делать это и в контексте функции синтаксического анализатора. Вот простой пример того, как это сделать:
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:
- Руководство:Разработка расширений , or for more general information about extensions, see Руководство:Расширения and Extensions FAQ .
- Руководство:Теги расширений
- Руководство:Волшебные слова
Code:
- Manual:Parser.php
- Manual:Hooks/ParserFirstCallInit
- Parser function hooks - (неполный) список функций парсера, предоставляемых ядром и расширениями
- Библиотека PHP Parser Hooks, которая предоставляет объектно-ориентированный интерфейс для декларативных крючков парсера
- Manual:Extension data
Examples:
- Расширение ParserFunctions - хорошо известный сборник функций парсера.
- Справка:Расширение:Функции парсера
- Категории:Расширения функций парсера