phpjadeで楽々(?)php


今回はphpを楽に書ける(かもしれない)ツール、phpjade を紹介します。
PHPはHTML文書内にロジックを混ぜて書く事が出来るのが強みですが、そうするとプログラムとしてもHTML文書としてもちょっと読みづらくなります。
読みづらいし、編集しづらいですね。
HTML自体、「もうちょっと何とかならんか?」と言いたくなるほど、人に優しくない文法だと思います、個人的には。

phpjadeは、nodejs1上のツールであるJade template engine のアドオンです。

Jade template engine(以下Jade) は簡単な記述からhtmlを生成出来るテンプレートエンジンです。
他の言語による移植もいくつか有るようです。
Jadeの有用性については「閉じタグ書かなくて良いよ」と言えばある程度分かってもらえるのでは無いかと思います。
jade言語で書いたテンプレートをjadeツールに渡す事で、htmlを生成する事が出来ます。
例を挙げてみます。

html
  body
    div Jadeで書いてみました。

ちなみにJadeには「必ず一定のインデントを入れる」という鉄則が有ります。
上の例ではインデントは空白2個、と決めていますが、利用者がおのおの勝手に決めて良いです。
このJadeソースから以下のようなhtmlが生成されます。

<html>
  <body>
    <div>Jadeで書いてみました。</div>
  </body>
</html>

一度Jadeのソースに慣れてしまうと、htmlそのままの記述が大変読みづらく思えます、当然書きづらくも感じます。

PHPを使いたい場合は以下のようになります。

html
  body
    div <?php echo 'JadeにPHPを混ぜてみました'; ?>

ここから以下のようなPHP文書が生成されます。

<html>
  <body>
    <div><?php echo 'JadeにPHPを混ぜてみました'; ?></div>
  </body>
</html>

これでも充分楽にはなっているのですが、せっかく ‘<‘ や ‘>’ を書かなくて良くなっているのに、PHPのタグだけそのまま書かなくてはなりません。
どうにかならないものだろうか?と考えた人が居て、「jade-php」というモジュールを開発されました。
phpjadeはこのjade-phpから派生して2作ったツールです。

phpjadeの基本的な仕様はjade-phpと同じですが、中身はほぼ書き直されており、いくつかの機能拡張も有ります。

以下に使用例を挙げながら機能を紹介していきたいと思います。
nodejsが既にお使いのシステムにインストールされていることが前提です、 nodejsのインストール関連のリンクを脚注に置いておきますので参考にしてください。3

まずは通常のJadeを使いながら使用感をつかんでもらって、phpjadeの説明に入ります。

まずJadeをインストール

nodejsのモジュール管理システムnpmを使ってJadeをインストールします。
お使いの環境のシェル上で、(Windowsであればコマンドプロンプト)以下のコマンドを打ちます。

npm install -g jade

もしかしたらエラーになるかもしれません。
管理者権限が無い旨のエラーだった場合は、管理者権限でコマンドを実行してください。
macosやLinuxなら、

sudo npm install -g jade

となります。

Jadeを使ってみます

ここからJadeを試します。
出来れば適当な作業ディレクトリを作って、そこへ移動します。
シェル上で

jade

と打ってみましょう。
何も返らないで止まった状態になると思います。
そこで、

html

とタイプし、CTRL-D を入力してみてください。
Windowsだと、「CTRL-Zの後に改行」 になります。

<html></html>

と出力されると思います。

ちなみに、オプション --help を付けるとコマンドラインオプションの一覧が出力されます。

  $ jade --help

    Usage: jade [options] [dir|file ...]

    Options:

      -h, --help         output usage information
      -V, --version      output the version number
      -O, --obj <str>    javascript options object
      -o, --out <dir>    output the compiled html to <dir>
      -p, --path <path>  filename used to resolve includes
      -P, --pretty       compile pretty html output
      -c, --client       compile function for client-side runtime.js
      -n, --name <str>   The name of the compiled template (requires --client)
      -D, --no-debug     compile without debugging (smaller functions)
      -w, --watch        watch files for changes and automatically re-render
      --name-after-file  Name the template after the last section of the file path (requires --client and overriden by --name)
      --doctype <str>    Specify the doctype on the command line (useful if it is not specified by the template)

    Examples:

      # translate jade the templates dir
      $ jade templates

      # create {foo,bar}.html
      $ jade {foo,bar}.jade

      # jade over stdio
      $ jade < my.jade > my.html

      # jade over stdio
      $ echo 'h1 Jade!' | jade

      # foo, bar dirs rendering to /tmp
      $ jade foo bar --out /tmp

Jadeに与える入力データを「Jadeテンプレート」と呼びます。
Jadeテンプレートは、上で紹介したように標準入力から与える事も出来ますし、Jadeテンプレートが記述されたファイル名や、複数のJadeテンプレートが置かれたディレクトリの名前を指定する事も出来ます。

それでは色々試してみましょう。
jadeを起動し、

html
body

と入力すると、

<html></html><body></body>

となります、しかしこんなHTMLは許されませんよね、bodyタグがhtmlタグの中に入っていません。
タグの間にタグを入れるには、インデントを付けます。
インデントは、空白やタブを使います。

html
  body

というふうに、とりあえず空白2個のインデントを付けてみます。

<html><body></body></html>

となるはずです。
ここで、出力が一行で出てしまうので嫌だと思う人も居るかもしれません。
jade の起動時引数 --prettyを付けると、出力もちゃんとインデントされます。

jade --pretty

で起動し、

doctype
html
  body

と入力すると、

<!DOCTYPE html>
<html>
  <body></body>
</html>

と出力されます。
上で使った「空白2個」のインデントは、「タブ1個」でも「空白8個」でもOKですが、そのJadeテン プレート内で一貫していないと予期しない動作になったりエラーになったりしますので注意が必要です。

html
      head
     body
      div

だと、

<html>
  <head></head>
</html>
<body>
  <div></div>
</body>

となってしまいます。

Jadeはいくつかのタグについての情報は内部に持っています、例えば上に挙げた doctype やbrの様な自前で閉じるタグなどです。
そのほかのタグについてはただ単に 「'<>’で囲んで閉じタグ'</>’を生成する」、というルールに則っているだけです。
ですので、でたらめなタグもちゃんと出力されます。

doctype
html
  body
    gomashio ふりかけ
    br
    funa 釣り
<!DOCTYPE html>
<html>
  <body>
    <gomashio>ふりかけ</gomashio>
    <br>
    <funa>釣り</funa>
  </body>
</html>

のように、あり得ないタグ'<gomashio>''<funa>'が出力されていますね。
ちなみに上の例に有る br タグは、doctype が付いていると '<br>'と出力され、doctypeが付いていないと'<br/>'と出力されます。
doctype はデフォルトで html5の<!doctype html>が出力されますが、

doctype  HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"

のように明示的にDTDを指定する事も出来ます。

HTMLのタグには属性が付くことが有ります。
Jadeでは、この属性についても省略記法を導入しています。
id属性とclass属性に関してのみ、以下のように書くことが出来ます。

div#comment.small

は、

<div id="comment" class="small"></div>

となります、id は #id で書けますし、classは.class で書けます。
また、class属性は以下のようにして複数書けます。

div#command.small.pop

は、

<div id="comment" class="small pop"></div>

となります。
これらの記法はもちろんdivタグに限らず他の全てのタグで使用出来ます。
id、class以外の属性に関しては、

div(role="main", prior="200") テスト文字列

のように書けます。
以下のような出力になります。

<div role="main" prior="200">テスト文字列</div>

Jadeの紹介の最後に、JavaScriptの利用について。
JadeテンプレートにはJavaScriptのスクリプトや式を含める事が出来ます。

html
  body
    - var myvalue = 100 + 1;
    div(prio="#{myvalue}") 優先度は#{myvalue}です。

のように、JavaScriptの実行文は ‘-‘ を頭に付けて、テキスト中の式などは’#{}’で囲んで記述出来ます。
上の例は以下のような出力になります。

<html>
  <body>
    <div prio="101">優先度は101です。</div>
  </body>
</html>

上の例でJavaScriptの変数’myvalue’を参照していますが、このようなJavaScriptのデータは外部からも与える事が出来ます。
jadeコマンドの起動時引数’–obj’ を使って、JavaScriptのデータを渡せます4

jade --pretty --obj '{ myvalue: "101" }'

のようにJadeを起動し、以下のJadeテンプレートを与えてみます。

html
  body
    div(prio="#{myvalue}") 優先度は#{myvalue}です。

前の例と同じ出力が得られるはずです。

phpjadeの使い方

Jadeにはまだ沢山有用な機能がありますが、それらはおいといてここからphpjadeを使ってみる事にします。
準備として、適当な作業ディレクトリに移動してください。
(作業ディレクトリの下にnpmモジュールがインストールされますので)
まず、Jadeのアドオンであるphpjadeをコマンドラインで使用するために、jade-mod というツールが必要になります。
jade-modはphpjadeの為に作ったツールですが、phpjade以外のアドオンにも使えます(ただ、まだこの形式のアドオンはphpjadeしか存在しません)

npm install -g jade-mod

これで jademodコマンドが使えるようになります。
(権限が無いためにエラーが出る場合は、管理者権限で実行します、unix系の場合は sudo で実行します)  
jademodコマンドは、完全にjadeコマンドと置き換え可能で、アドオンの為のオプションが追加されているだけです。
次に phpjadeモジュールを、ローカル環境にインストールします。
jade-modはコマンドラインツールなので使い勝手を考えてグローバルにインストールしますが、phpjadeはローカルインストールで問題ありません。
以下のコマンドを実行すると、作業ディレクトリの下にphpjadeモジュールがインストールされます。

npm install phpjade

使ってみましょう。

jademod

と実行すると、全くjadeコマンドと同じ動作をします、phpjadeも使えません。
-M phpjadeとオプションを追加する事により、phpjadeとして動作します。
このオプションを付けると、jademodコマンドはphpjadeモジュールをロードし、jadeモジュールに適用してその後はjadeモジュールが動作する事になります。

phpjadeらしい事をしてみます。

jademod --pretty -M phpjade

とjademodを実行し、jadeのときと同じようにテンプレートを与えてあげます。

html
  body
    - foreach ($myarray as $elem) :
    div!=$elem
    - endforeach

以下のような出力が得られます。

<html>
  <body>
    <?php foreach ($myarray as $elem) : ?>
    <div>
      <?php echo $elem; ?></div>
    <?php endforeach; ?>
  </body>
</html>

ちょっとdivのインデントが残念な感じですが(php echo $elemの前は改行されないのが正しいのですが)、簡単な記述からPHPが生成されました。
PHPコードの前後のインデントについては、今後改善する予定です。

別の例を見ていきましょう。
属性にPHPコードを入れる例

div(ops=php_function())

は、

<div ops="<?php echo htmlspecialchars(php_function(), ENT_QUOTES, 'UTF-8'); ?>"></div>

と出力されます。
属性値の部分が""''で囲まれていない場合、自動的にPHPのコードと見なされます。
ただしデフォルトで echo htmlspecialchars( ) が付加されますので、記述したPHPコードが直接HTMLセーフな文字列を返す場合、

div(ops!=php_function())

のように !を付けると、

<div ops="<?php echo php_function(); ?>"></div>

となります。

echoも不要なときは、ちょっと不自然な書式ですが、

div(ops!=-php_function())

と、PHPコードの前に -を付けます。
以下のように出力されます。

<div ops="<?php php_function(); ?>"></div>

PHPで、たまに属性名と属性値の両方をPHPコードで出力している場合があります。
このようなときもphpjadeは対応出来ます、ただし現在起動時オプションに設定が必要になっていますので、 jademod起動時に引数を追加してやります4
(将来的には不要にしたいです)

jademod --pretty -M phpjade --obj '{usestrip:true}'

のようにjademodを起動し、テンプレートを与えてやります。

div(__=php_function())

以下のような出力になります。

<div <?php php_function(); ?> ></div>

上記の様な出力が一つのタグに複数必要な場合、アンダースコア('_')を増やします、一つのタグに同じ名前の属性を複数書けないからです。

div(__=php_function1(), ___=php_function2())

以下の出力が得られます。

<div <?php php_function2(); ?>  <?php php_function1(); ?> ></div>

phpjadeでは、Jadeに於ける’code’部分をphpコードと見なします、そのため通常のJadeの様に’code’部分にJavaScriptを書く事は出来ません、ただし、式の使用は#{}で記述する事が出来ます。

jademod --pretty -M phpjade --obj '{ns:"mytheme"}'
- namespace #{ns};
<?php namespace mytheme; ?>

phpjadeのちょっと変わった機能として、prefilterがあります。
prefilterはテンプレート内のPHPコードとして解釈される文字列を自前のJavaScript関数で変換する事が出来る機能です。
これを使うと、例えばWordPressのテーマなどによく見かける、「しょっちゅう出てくるけど省略出来ない文字列」を短くする事が出来ます。

jademod --pretty -M phpjade --obj '{prefilter: function(src) { return src.replace(/ZZ/g,"mythemename"); }}'

のようにprefilter関数を与えます4
そしてテンプレートに、

- echo _("English text", "ZZ")

と書けば、

<?php echo _("English text", "mythemename"); ?>

と出力されます。
(実際は”ZZ”のようなありふれた文字列を置換文字列に割り当てるのは危険ですので、他の場所で使われなさそうな文字列を選んでください。)

大体以上がphpjadeの紹介となります。
今回はphpjadeを使用するために jademodコマンドを使用しましたが、このほかにも Grunt5で使用するためのgrunt-jade-mod6モジュールや、
Gulp7で使用するためのgulp-phpjade8モジュールもあります。
また、このphpjadeを使用したWordPressテーマのひな形9も公開していますので、興味のある方はチェックしてみてください。


  1. node.js
    今更説明は不要と思いますが、JavaScript の実行環境です。
    JavaScriptと言えばWebブラウザ上で動作するスクリプト言語として知られていますが、このnode.jsはサーバシステムやデスクトップアプリケーションの記述にJavaScriptを使用する事の出来るシステムです。
    node.js上で動作する大量のアプリケーションが提供されています。 
  2. jade-phpを使ってみたところ、その仕様は良い感じに思えたのですが、Jadeの持ついくつかの便利機能が使えなかったりして(2015年5月時点)、自前で書き直すことにしました。
    ちょっとしたバグ修正ならphp-jadeの作者さんにpull-requestを出せば良かったのですが、修正を始めたらほぼ書き直しになってしまい、別モジュールとして発表することにしました。 
  3. nodejsのインストール
    本家
    Windowsでのインストール方法例
    Macosでの例、brew前提
    Ubuntuの例 
  4. --obj 引数のパラメータにはJavaScriptの文字列だけで無く、JavaScriptの値が書かれたファイル名も渡す事が出来ます。
    例えばdata.jsという以下のようなファイルを作成して、

    
    {
      myobj: { val1: "abc", val2: "def"},
      myfunc: function(arg1) {return "xyz";}
    }
    

    jadeもしくはjademodコマンドに以下のように渡せます。

    
      jade --obj data.js
    

  5. Gruntはnodejs上で使用されるビルドツールです。 
  6. Gruntでphpjadeを使用するためのタスクモジュールです。
    grunt-jade-mod 
  7. Gulpはnodejs上で使用されるビルドツールです。 
  8. Gulpでphpjadeを使用するためのモジュールです。
    私が作ったものでは無いので詳細は分かりません。
    gulp-phpjade 
  9. wptt(WordPress Theme Template)
    wptt