Hướng dẫn:Hàm phân tích cú pháp
Các hàm phân tích cú pháp được thêm vào trong MediaWiki 1.7, là một loại tiệ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:Tiện ích mở rộng:ParserFunctions .)
Miêu tả
Trong khi phần mở rộng thẻ 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ố bản mẫu hoặc trong việc xây dựng liên kết.
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 tài liệu 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 số đầu tiên của hàm gọi chuyển tất cả các đối số dưới dạng văn bản thuần túy.
Biến số thứ hai bỏ qua các luận lý như một mảng của PPNode , ngoại trừ biến thứ nhất ($args[0]
), hiện đang là văn bản, mặc dù điều này có thể thay đổi sau.
Chúng đại diện cho mã wiki chưa được mở rộng.
Tham số $frame
có thể được sử dụng để mở rộng các luận lý này khi cần.
Phần này thường được sử dụng để xử lý điều kiện, do đó chỉ các trường hợp "true" mới được đánh giá bằng hàm phân tích cú pháp giống if hoặc switch.
Đối tượng frame còn có thể trèo lên cây tài liệu để lấy thông tin về hàm gọi và có các hàm để xác định và quản lý độ sâu hàm gọi, time-to-live và liệu kết quả của hàm 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ợ nhiều tên giả và khả năng địa phương hóa.
Ví dụ đơn giản
Dưới đây là một ví dụ về tiện ích mở rộng tạo ra chức năng phân tích cú pháp.
Việc đăng ký được đặt trong extension.json và mã nguồn được đặt trong 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ỳ callback render 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à mã wiki.
$output = "param1 is $param1 and param2 is $param2 and param3 is $param3";
return $output;
}
}
Một tập tin 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}}
cho ra:
- param1 là hello và param2 là hi và param3 là hey
LocalSettings.php
MediaWiki\MediaWikiServices::getInstance()->getContentLanguage()->mMagicExtensions['wikicodeToHtml'] = ['MAG_CUSTOM', 'custom'];
Trong 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"
}
- Xem: viết trình xử lý sự kiện để biết các kiểu khác.
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' ] );
}
}
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. Values:
- 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
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:
Name | Type | Default | Description |
---|---|---|---|
found | Boolean | true
|
true if the text returned is valid and processing of the template must stop.
|
text | ? | ? | The text to return from the function. If isChildObj or isLocalObj are specified, this should be a DOM node instead. |
noparse | Boolean | true
|
true if text should not be preprocessed to a DOM tree, e.g. unsafe HTML tags should not be stripped, etc.
|
isHTML | Boolean | ? | true if the returned text is HTML and must be armoured against wikitext transformation. But see discussion
|
nowiki | Boolean | usually false
|
true if wiki markup in the return value (text) should be escaped.
|
isChildObj | Boolean | ? | true if the text is a DOM node needing expansion in a child frame.
|
isLocalObj | Boolean | ? | true if the 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.
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
General and related guides:
- Thủ công:Dịch phần mở rộng , or for more general information about extensions, see Hướng dẫn sử dụng: Tiện ích mở rộng and Extensions FAQ .
- Manual:Tag extensions
- Hướng dẫn:Từ ma thuật
Code:
- Manual:Parser.php
- Manual:Hooks/ParserFirstCallInit
- Parser function hooks - an (incomplete) list of parser functions provided by core and extensions
- The Parser Hooks PHP library, which provides an object orientated interface for declarative parser hooks
Examples:
- The ParserFunctions extension is a well-known collection of parser functions.
- Trợ giúp:Tiện ích mở rộng:ParserFunctions