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

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
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"
}
- 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' ] );
}
}
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
- Manual:Hooks/ParserFirstCallInit
- Hướng dẫn sử dụng: Tiện ích mở rộng
- Manual:Tag extensions
- Hướng dẫn:Từ ma thuật
- Manual:Parser.php
- Extensions FAQ
- Trợ giúp:Mở rộng:ParserFunctions
- The ParserFunctions extension is a well-known collection of parser functions.
- 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