Posted at

初めてのXHP


XHP

Hackといえば、XHPというイメージを持つ方も多いのではないでしょうか

XHPはXMLライクに記述し、UIに関するコードの型チェックを行うことができる様もので、

記法自体はReactとほぼ同じものです。

React自体に慣れている方は簡単に利用ができるのではないでしょうか。

このため、Hackを利用する場合はHTMLテンプレートライブラリを使うメリットがあまりありません。


XHPを利用するには

XHPをフル活用するには、xhp-libをcomposer経由でインストールしておく必要があります。


composer.json

"require": {

"facebook/xhp-lib": "~2.2"
}

または、下記のコマンドになります。

$ hhvm $(which composer) require facebook/xhp-lib


書き方

入門ということで、書き方からみていきましょう。

PHPの標準的なHTML出力は次のようの記述します。

<?hh

$user_name = 'Fred';
echo "<tt>Hello <strong>$user_name</strong></tt>";

XHPでは以下となります。

<<__Entrypoint>>

function run(): void {
$user_name = 'Hack / XHP';
echo <tt>Hello <strong>{$user_name}</strong></tt>;
}

PHPではシンタックスエラーになる書き方ですので、

これもまた難解なイメージがあるかもしれません。

誤ったタグを記載すると、Typecheckerで警告が出ますので、

記述ミスなども防ぐことができます。

次の様に誤っタグを混在させると、エラーとなります。

echo <body><tt>Hello <strong>{$user_name}</strong></tt></bod>;

[Hack] Parsing[1002] XHP: mismatched tag: 'bod' not the same as 'body' [1002]


セキュリティについて

XHPを利用する場合、HTTP Requestなどで悪意のある文字列などに対応するため、

デフォルトでエスケープが有効になっています。

    $user_name = '<a href="javascript:alert(\'lol\')">javascript:alert(\'lol\')</a>';

echo <tt>Hello <strong>{$user_name}</strong></tt>;

特定の部分でエスケープを無効にする場合は、

XHPUnsafeRenderableインターフェースを実装した要素の描画クラスを用意します。

final class ExampleUnsafeRender implements XHPUnsafeRenderable {

public function __construct(
private string $html,
) {
}

public function toHTMLString(): string {
return $this->html;
}
}

さきほどのXHPへの埋め込みは次の通りです。

require __DIR__ .'/vendor/hh_autoload.php';

<<__Entrypoint>>
function run(): void {
$user_name = '<a href="javascript:alert(\'hacked!\')">javascript:alert(\'hacked!\')</a>';
echo <tt>Hello <strong>{new ExampleUnsafeRender($user_name)}</strong></tt>;}


Reactライクに記述する

JSXと同等に小さく要素を切り出し、再利用しやすい形にできます。

要素を作成する場合は、:x:element を継承する必要があります。

これまたPHPではありえないシンタックスになりますので、

違和感が感じられる方も多いでしょう。

ちゃんと動作するので大丈夫です!


src/Acme/Render/Hoge.php

<?hh // strict

class :hoge extends :x:element {
protected function render(): \XHPRoot {
return <strong>hoge!</strong>;
}
}


作成した要素は、hh-autoload経由(hhvm/hhvm-autoload)で利用できます。

:hoge は、<hoge/> として埋め込むことができます。

<?hh 

require __DIR__ .'/vendor/hh_autoload.php';

<<__Entrypoint>>
function run(): void {
echo <hoge/>;
echo <hoge/>;
echo <hoge/>;
}

VSCのHack plugin や、

Nuclideを利用している方は要素からクラスへジャンプすることなどができます。

まずは基本の記法をしっかりと理解しておきましょう。