Thủ công:Hàm phân tích cú pháp

From mediawiki.org
This page is a translated version of the page Manual:Parser functions and the translation is 49% complete.
MediaWiki extensions

Các hàm trình phân tích cú pháp, được thêm vào trong MediaWiki 1.7, là một loại phần mở rộng tích hợp chặt chẽ với trình phân tích cú pháp. Không nên nhầm lẫn cụm từ "hàm phân tích cú pháp" với Extension:ParserFunctions , đây là tập hợp các hàm phân tích cú pháp đơn giản. (Xem Trợ giúp:Mở rộng:ParserFunctions cho những.)

Diễn giải

Trong khi thẻ(tag) mở rộng được dự kiến ​​sẽ lấy văn bản chưa được xử lý và trả lại HTML cho trình duyệt, chức năng phân tích cú pháp có thể 'tương tác' với các phần tử wiki khác trong trang. Ví dụ: đầu ra của hàm trình phân tích cú pháp có thể được sử dụng làm tham số mẫu hoặc trong việc xây dựng link.

Cú pháp điển hình cho một hàm phân tích cú pháp là:

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

Để biết thêm thông tin, hãy xem the documentation cho Parser::setFunctionHook ( $id, $callback, $flags = 0 ). Tài liệu này nêu rõ:

Hàm gọi lại phải có dạng:
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
Hoặc với SFH_OBJECT_ARGS:
function myParserFunction( $parser, $frame, $args ) { ... }

Biến thể đầu tiên của cuộc gọi chuyển tất cả các đối số dưới dạng văn bản thuần túy. 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. Chúng đại diện cho wikitext chưa được mở rộng. The $frame parameter can be used to expand these arguments as needed. Điều này thường được sử dụng để xử lý có điều kiện sao cho chỉ trường hợp "true" mới được đánh giá bằng hàm trình phân tích cú pháp giống như if hoặc switch. Đối tượng khung cũng có thể leo lên cây tài liệu để lấy thông tin về người gọi và có chức năng xác định và quản lý độ sâu cuộc gọi, thời gian tồn tại và liệu kết quả của chức năng trình phân tích cú pháp có biến động hay không.

Việc tạo hàm phân tích cú pháp phức tạp hơn một chút so với việc tạo thẻ mới vì tên hàm phải là từ ma thuật, một từ khóa hỗ trợ bí danh và bản địa hóa.

Ví dụ đơn giản

Dưới đây là một ví dụ về tiện ích mở rộng tạo chức năng trình phân tích cú pháp.

Đăng ký chuyển thành extension.json và mã thành src/ExampleExtensionHooks.php tương ứng:

{
	"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 {
   // Đăng ký bất kỳ lệnh gọi lại kết xuất nào với trình phân tích cú pháp
   public static function onParserFirstCallInit( Parser $parser ) {

      // Tạo một hook hàm liên kết từ ma thuật "ví dụ" với renderExample()
      $parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
   }

   // Kết xuất đầu ra của {{#example:}}.
   public static function renderExample( Parser $parser, $param1 = '', $param2 = '', $param3 = '' ) {

      // Các tham số đầu vào là wikitext với các bản mẫu được mở rộng.
      // Đầu ra cũng phải là wikitext.
      $output = "param1 is $param1 and param2 is $param2 and param3 is $param3";

      return $output;
   }
}

Một tệp khác, ExampleExtension.i18n.php, trong thư mục mở rộng của bạn (Không có trong thư mục con src/) sẽ chứa:

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

$magicWords = [];

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

Khi tiện ích mở rộng này được bật,

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

sản xuất:

  • param1 is hello and param2 is hi and param3 is hey
Mảng MagicWords này không phải là tùy chọn. Nếu nó bị bỏ qua, chức năng phân tích cú pháp sẽ không hoạt động; mảng $ sẽ được hiển thị như thể tiện ích mở rộng chưa được cài đặt. Nếu chỉ mảng dành riêng cho ngôn ngữ được khởi tạo chứ không phải chính mảng magicWords, thì điều này có thể gây ra lỗi bản địa hóa khi bản dịch từ các tiện ích mở rộng khác rò rỉ sang phần mở rộng của bạn. Bạn có thể liên kết các từ ma thuật nội tuyến trong PHP thay vì thông qua tệp i18n. Điều này rất hữu ích khi xác định hook trong 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];
}

Chức năng dài hơn

Đối với các hàm dài hơn, bạn có thể muốn tách các hàm hook thành tệp _body.php hoặc .hooks.php và biến chúng thành các hàm tĩnh của một lớp. Sau đó, bạn có thể tải lớp bằng $wgAutoloadClasses và gọi các hàm tĩnh trong móc nối(hook); ví dụ.:

Đặt cái này vào tệp extension.json của bạn:

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

Sau đó đặt cái này vào tệp src/ExampleExtensionHooks.php của bạn:

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

Bộ nhớ đệm

Như với phần thẻ mở rộng , $parser->disableCache() có thể được sử dụng để vô hiệu hóa bộ nhớ đệm cho các phần mở rộng động. (deprecated in 1.28)

Điều này có tác động tiêu cực đáng kể đến hiệu suất, vì vậy chỉ sử dụng khi cần thiết.

Giao diện trình phân tích cú pháp

Kiểm soát phân tích cú pháp đầu ra

Để văn bản wiki do hàm trình phân tích cú pháp của bạn trả về được phân tích cú pháp đầy đủ (bao gồm cả phần mở rộng của bản mẫu), hãy đặt tùy chọn noparse thành `false` khi trả về:

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

Có vẻ như giá trị mặc định cho noparse đã thay đổi từ sai thành đúng, ít nhất là trong một số trường hợp, vào khoảng phiên bản 1.12.

Ngược lại, để hàm phân tích cú pháp của bạn trả về HTML vẫn chưa được phân tích cú pháp, thay vì trả về wikitext, hãy sử dụng:

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

Naming

Theo mặc định, MW thêm một ký tự băm (ký hiệu số, "#") vào tên của mỗi chức năng trình phân tích cú pháp. Để loại bỏ phần bổ sung đó (và lấy hàm trình phân tích cú pháp không có tiền tố "#"), hãy bao gồm hằng số SFH_NO_HASH trong đối số cờ tùy chọn cho setFunctionHook, như được mô tả bên dưới.

Khi chọn một tên không có tiền tố băm, hãy lưu ý rằng việc nhúng một trang có tên bắt đầu bằng tên hàm đó theo sau bởi dấu hai chấm là không thể nữa. Đặc biệt, tránh đặt tên hàm bằng tên không gian tên. Trong trường hợp bật tính năng chuyển ngữ liên wiki [1], cũng nên tránh các tên hàm tương đương với tiền tố liên wiki.

The setFunctionHook hook

For more details of the interface into the parser, see the documentation for setFunctionHook in includes/Parser.php. Here's a (possibly dated) copy of those comments:

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

Parameters:

  • string $id - The magic word ID
  • mixed $callback - The callback function (and object) to use
  • integer $flags - Optional, set it to the SFH_NO_HASH constant to call the function without "#".

Return value: The old callback function for this name, if any

Create a function, e.g., {{#sum:1|2|3}}. The callback function should have the form:

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

The callback may either return the text result of the function, or an array with the text in element 0, and a number of flags in the other elements. The names of the flags are specified in the keys. Valid flags are:

forceRawInterwiki
Force interwiki transclusion to be done in raw mode, not rendered.
found
The text returned is valid, stop processing the template. This is on by default.
isChildObj
The text is a DOM node needing expansion in a child frame.
isHTML
The returned text is HTML, armour it against wikitext transformation. But see discussion
isLocalObj
The text is a DOM node needing expansion in the current frame.
noparse
Unsafe HTML tags should not be stripped, etc.
nowiki
Wiki markup in the return value should be escaped.
preprocessFlags
Use these flags when parsing the returned text. This only applies when noparse is false.
text
The text returned from the function. If isChildObj or isLocalObj are specified, this should be a DOM node instead.
title
The Title object where the text came from.

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.

Named parameters

Parser functions do not support named parameters the way templates and tag extensions do, but it is occasionally useful to fake it. Users are often accustomed to using vertical bars ( | ) to separate arguments, so it's nice to be able to do that in the parser function context, too. Here's a simple example of how to accomplish this:

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;
}

See also

  • The Parser Hooks PHP library, which provides an object orientated interface for declarative parser hooks