XHP:擴展

2018-10-18 11:14 更新

XHP附帶了所有標準HTML標簽的類,但是由于這些是一流的對象,因此可以創(chuàng)建自己的XHP類來呈現(xiàn)不符合標準HTML規(guī)范的項目。

基本

所有XHP類名以冒號開始,:并且可以包括其他:,只要它們不相鄰。請注意,這是Hack規(guī)則的一個例外,您不能:在類名中。

一個自定義的XHP類需要做兩件事情:

  • 延伸:x:element。
  • 實現(xiàn)render()通過XHP對象返回的方法XHPRoot。
<?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屬性支持以下類型:

  • bool,int,float,string,array,mixed(有沒有強制 ......一個int不強迫float,例如,你會得到一個XHPInvalidAttributeException,如果你試試這個)。
  • Hack enum 名稱
  • XHP特定enums與該屬性的內聯(lián)形式enum {item, item...}。所有值必須是標量的,因此可以將其轉換為字符串。這些枚舉不是Hack enums。
  • 類或接口名稱
  • 通用類型,帶有類型參數(shù)

如果屬性在實例化元素時屬性不正確,則類型檢查器會引發(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;

Inheritance

在自定義XHP類中擁有屬性的最簡單的方法是繼承現(xiàn)有XHP對象的屬性是使用XHPHelperstrait。

Children

您應該聲明自定義類允許的類型作為子集。你使用的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>&quot;Hello!&quot;</em>

Async

XHP和 async共同共存。 async XHP類必須做另外兩件事情:

  • 使用XHPAsync特質
  • 實施asyncRender(): Awaitable<XHPRoot>而不是render(): XHPRoot
<?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: &lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot; id=&quot;facebook&quot; class=&quot;no"

XHP Helpers

該XHPHelpers特性實現(xiàn)了三種行為:

  • 將屬性從一個對象傳遞到從其render()方法返回的對象。
  • 給每個對象一個唯一的id屬性。
  • 管理class屬性。

屬性轉移

假設你有一個類要繼承屬性: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()。

唯一ID

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>
以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號