Руководство:Функции парсера

Функции парсера, добавленные в MediaWiki 1.7, представляют собой тип расширения, тесно интегрированного с парсером. Фразу "функция парсера" не следует путать с Расширение:ParserFunctions , которая представляет собой набор простых функций парсера. (Смотрите Справка:Расширение:Функции Парсера для этого.)
Описание
В то время как теги расширений обрабатывают необработанный текст и возвращают 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 соответственно:
{
"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 ) {
// Создайте функциональный крючок, связывающий волшебное слово "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;
}
}
Другой файл, 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' ] );
}
}
Кэширование
Как и в случае расширения тега, $parser->disableCache()
может использоваться для отключения кэша для динамического расширения.
(устарело в 1.28)
Это оказывает значительное негативное влияние на производительность, поэтому используйте его только в случае необходимости.
Интерфейс парсера
Контролирование вывода парсера
Чтобы викитекст, возвращаемые функцией парсер быть полностью разбираемый (в том числе расширение шаблонов), установите параметр 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 для вызова функции без "#".
Возвращаемое значение: Старая функция обратного вызова для этого имени, если есть
Создайте функцию, например, {{#sum:1|2|3}}
. Функция обратного вызова должна иметь вид:
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
Обратный вызов может либо возвращать текстовый результат функции, либо массив с текстом в элементе 0 и рядом флагов в других элементах. Имена флагов указаны в ключах. Допустимые флаги:
- forceRawInterwiki
- Принудительное включение интервики в необработанном режиме, а не в режиме рендеринга.
- found
- Возвращаемый текст действителен, прекращает обработку шаблона. Это включено по умолчанию.
- isChildObj
- Текст представляет собой узел DOM, требующий расширения в дочернем фрейме.
- isHTML
- Возвращаемый текст представляет собой HTML, защищает его от преобразования в викитекст. Но см. обсуждение
- isLocalObj
- Текст представляет собой узел DOM, требующий расширения в текущей рамке.
- noparse
- Небезопасные теги HTML не должны удаляться и т. д.
- nowiki
- Вики-разметка в возвращаемом значении должна быть экранирована.
- preprocessFlags
- Используйте эти флаги при анализе возвращаемого текста. Это применимо только тогда, когда noparse равен
false
. - text
- Текст, возвращаемый функцией. Если указаны isChildObj или isLocalObj, это должен быть узел DOM.
- title
- Объект Title, из которого был взят текст.
Затратные функции парсера
Некоторые функции парсера требуют значительного использования ресурсов вики и должны быть помечены как "затратные". Количество затратных функций парсера на любой данной странице ограничено настройкой $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;
}
См. также
- Manual:Hooks/ParserFirstCallInit
- Руководство:Расширения
- Руководство:Теги расширений
- Руководство:Волшебные слова
- Manual:Parser.php
- Extensions FAQ
- Справка:Расширение:Функции Парсера
- Расширение ParserFunctions - хорошо известный сборник функций парсера.
- Parser function hooks - (неполный) список функций парсера, предоставляемых ядром и расширениями
- Библиотека PHP Parser Hooks, которая предоставляет объектно-ориентированный интерфейс для декларативных крючков парсера