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

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

Функции парсера, добавленные в 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 соответственно:

{
	"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
Это magicWords массива является обязательным. Если он опущен, функция парсера просто не будет работать; в {{#example: hello | hi}} будут отображены так, как будто расширение не установлено. Если инициализируется только массив для конкретного языка, а не сам массив magicWords, это может вызвать ошибки локализации, поскольку переводы из других расширений просачиваются в ваш. Вы можете связать волшебные слова прямо в PHP, а не через файл i18n. Это полезно при определении хуков в 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 для вызова функции без "#".

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 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:

Code:

Examples: