XHP附帶了所有標準HTML標簽的類,但是由于這些是一流的對象,因此可以創(chuàng)建自己的XHP類來呈現(xiàn)不符合標準HTML規(guī)范的項目。
所有XHP類名以冒號開始,:并且可以包括其他:,只要它們不相鄰。請注意,這是Hack規(guī)則的一個例外,您不能:在類名中。
一個自定義的XHP類需要做兩件事情:
<?hh
class :introduction extends :x:element {
protected function render(): \XHPRoot {
return <strong>Hello!</strong>;
}
}
class :intro-plain-str extends :x:element {
protected function render(): \XHPRoot {
// Since this function returns an XHPRoot, if you want to return a primitive
// like a string, wrap it around <x:frag>
return <x:frag>Hello!</x:frag>;
}
}
function extending_examples_basic_run(): void {
echo <introduction />;
echo PHP_EOL . PHP_EOL;
echo <intro-plain-str />;
}
extending_examples_basic_run();
Output
<strong>Hello!</strong>
Hello!
您的自定義類可能具有與XML屬性類似的屬性,使用attribute關鍵字:
attribute <type> <name> [= default value|@required];
另外,可以組合多個聲明:
attribute
int foo,
string bar @required;
XHP屬性支持以下類型:
如果屬性在實例化元素時屬性不正確,則類型檢查器會引發(fā)錯誤(例如<a href={true} />,因為XHP允許以其他方式設置屬性(例如setAttribute()),并不是所有問題都可以被類型檢查器捕獲,并且XHPInvalidAttributeException將在運行時拋出,案例。
該->:運營商可以用來檢索屬性的值,而哈克將了解它的類型。
您可以@required根據屬性名稱后面的聲明指定屬性。如果您嘗試呈現(xiàn)XHP對象并且尚未設置必需屬性,則將XHPAttributeRequiredException拋出一個。
<?hh
class :user-info extends :x:element {
attribute int userid @required;
attribute string name = "";
protected function render(): \XHPRoot {
return
<x:frag>User with id {$this->:userid} has name {$this->:name}</x:frag>;
}
}
function extending_examples_attributes_run(): void {
$uinfo = <user-info />;
// Can't render :user-info for an echo without setting the required userid
// attribute
try {
echo $uinfo;
} catch (\XHPAttributeRequiredException $ex) {
var_dump($ex->getMessage());
}
$uinfo->setAttribute('userid', 1000);
$uinfo->setAttribute('name', 'Joel');
echo $uinfo;
}
extending_examples_attributes_run();
Output
string(166) "Required attribute `userid` was not specified in element `user-info`.
/data/users/joelm/user-documentation/guides/hack/24-XHP/04-extending-examples/required-attributes.php:16"
User with id 1000 has name Joel
由于歷史原因,可以推斷出可以使用的類型,而不是明確說明。如果屬性不是@required并且沒有默認值,則屬性為空。例如:
attribute
string iAmNotNullable @required,
string iAmNotNullableEither = "foo",
string butIAmNullable;
在自定義XHP類中擁有屬性的最簡單的方法是繼承現(xiàn)有XHP對象的屬性是使用XHPHelpers
trait。
您應該聲明自定義類允許的類型作為子集。你使用的children
聲明:
children (:class1, :class2);
children empty; // no children allowed
如果您沒有明確聲明使用該children屬性,那么您的類可以有任何小孩。如果您嘗試將子集添加到不允許某個對象或不在其聲明列表中的對象,那么XHPInvalidChildrenException將被拋出。
您可以在聲明children時使用標準的正則表達式運算符*
(zero or more), +
(one or more) |
(this or that)
<?hh
class :my-br extends :x:element {
children empty; // no children allowed
protected function render(): \XHPRoot {
return
<x:frag>PHP_EOL</x:frag>;
}
}
class :my-ul extends :x:element {
children (:li)+; // one more more
protected function render(): \XHPRoot {
return
<ul>{$this->getChildren()}</ul>;
}
}
class :my-html extends :x:element {
children (:head, :body);
protected function render(): \XHPRoot {
return
<html>{$this->getChildren()}</html>;
}
}
function extending_examples_children_run(): void {
$my_br = <my-br />;
// Even though my-br does not take any children, you can still call the
// appendChild method with no consequences. The consequence will come when
// you try to render the object by something like an echo.
$my_br->appendChild(<ul />);
try {
echo $my_br;
} catch (\XHPInvalidChildrenException $ex) {
var_dump($ex->getMessage());
}
$my_ul = <my-ul />;
$my_ul->appendChild(<li />);
$my_ul->appendChild(<li />);
echo $my_ul;
echo PHP_EOL;
$my_html = <my-html />;
$my_html->appendChild(<head />);
$my_html->appendChild(<body />);
echo $my_html;
}
extending_examples_children_run();
Output
string(240) "Element `my-br` was rendered with invalid children.
/data/users/joelm/user-documentation/guides/hack/24-XHP/04-extending-examples/children.php:33
Verified 0 children before failing.
Children expected:
empty
Children received:
:ul[%flow]"
<ul><li></li><li></li></ul>
<html><head></head><body></body></html>
XHP中的類別就像面向對象語言中的接口。您可以使用任何數(shù)量的類別標記您的自定義課程,然后可以從您的孩子引用。你使用category聲明。每個類別都有一個前綴%。
category %name1, %name2,...., %$nameN;
類別取自HTML規(guī)范(例如%flow,,%phrase)。
<?hh
class :my-text extends :x:element {
category %phrase;
children (pcdata | %phrase); // prefixed colon ommitted purposely on pcdata
protected function render(): \XHPRoot {
return
<x:frag>{$this->getChildren('%phrase')}</x:frag>;
}
}
function extending_examples_categories_run(): void {
$my_text = <my-text />;
$my_text->appendChild(<em>"Hello!"</em>); // This is a %phrase
echo $my_text;
$my_text = <my-text />;
$my_text->appendChild("Bye!"); // This is pcdata, not a phrase
// Won't print out "Bye!" because render is only returing %phrase children
echo $my_text;
}
extending_examples_categories_run();
Output
<em>"Hello!"</em>
XHP和 async共同共存。 async XHP類必須做另外兩件事情:
<?hh
class :ui:get-status extends :x:element {
use XHPAsync;
protected async function asyncRender(): Awaitable<\XHPRoot> {
$ch = curl_init('https://developers.facebook.com/status/');
curl_setopt(
$ch,
CURLOPT_USERAGENT,
'hhvm/user-documentation example',
);
$status = await HH\Asio\curl_exec($ch);
return <x:frag>Status is: {$status}</x:frag>;
}
}
function extending_examples_async_run(): void {
$status = <ui:get-status />;
// This can be long, so just show a bit for illustrative purposes
$sub_status = substr($status, 0, 100);
var_dump($sub_status);
}
extending_examples_async_run();
Output
string(100) "Status is: <!DOCTYPE html>
<html lang="en" id="facebook" class="no"
該XHPHelpers特性實現(xiàn)了三種行為:
假設你有一個類要繼承屬性:div。你可以這樣做:
<?hh
class :ui-my-box extends :x:element {
attribute :div; // inherit from attributes from <div>
protected function render(): \XHPRoot {
// returning this will ignore any attribute set on this custom object
// They are not transferred automically when returning the <div>
return
<div class="my-box">{$this->getChildren()}</div>;
}
}
function extending_examples_bad_attribute_transfer_run(): void {
$my_box = <ui-my-box title="My box" />;
// This will only bring <div class="my-box"></div> ... title= will be
// ignored.
echo $my_box->toString();
}
extending_examples_bad_attribute_transfer_run();
Output
<div class="my-box"></div>
上面的問題是,任何設置的屬性:ui:my-custom都將丟失,因為<div>返回的render()屬性將不會自動獲取這些屬性。
相反,你應該使用XHPHelpers。
<?hh
class :ui-my-good-box extends :x:element {
attribute :div; // inherit from attributes from <div>
// Make sure that attributes are transferred automatically when rendering.
use XHPHelpers;
protected function render(): \XHPRoot {
// returning this will transfer any attribute set on this custom object
return
<div class="my-good-box">{$this->getChildren()}</div>;
}
}
function extending_examples_good_attribute_transfer_run(): void {
$my_box = <ui-my-good-box title="My Good box" />;
echo $my_box->toString();
}
extending_examples_good_attribute_transfer_run();
Output
<div class="my-good-box" title="My Good box"></div>
現(xiàn)在,:ui:my-custom
渲染時,每個:div
屬性將被轉移,假定它在render()
函數(shù)中聲明。此外,設置的:ui:my-custom
屬性值將覆蓋函數(shù)中:div
設置的相同屬性render()
。
XHPHelpers有一種方法getID(),您可以調用它給您的渲染的自定義XHP對象一個唯一的ID,可以在您的代碼或UI框架的其他部分(例如CSS)中引用。
<?hh
class :my-id extends :x:element {
attribute string id;
use XHPHelpers;
protected function render(): \XHPRoot {
return
<span id={$this->getID()}>This has a random id</span>;
}
}
function extending_examples_get_id_run(): void {
// This will print something like:
// <span id="8b95a23bc0">This has a random id</span>
echo <my-id />;
}
extending_examples_get_id_run();
Output
<span id="d5f52c9291">This has a random id</span>
XHPHelpers有兩種方法可以將類名添加到classXHP對象的屬性中。這一切都假定您的自定義類class直接聲明或通過繼承聲明該屬性。addClass()采取string并附string加到class屬性; conditionClass()將a string和a bool追加string到class屬性,如果bool是true。
<?hh
class :my-cls-adder extends :x:element {
attribute :div;
use XHPHelpers;
protected function render(): \XHPRoot {
$div = <div />;
$div->addClass('my-cls-adder');
$div->appendChild($this->getChildren());
return $div;
}
}
function extending_examples_add_class_run(): void {
echo <my-cls-adder />;
}
extending_examples_add_class_run();
Output
<div class="my-cls-adder"></div>
更多建議: