zenith: 2007年12月アーカイブ

XML Inclusions (XInclude)を使ったテンプレートのレイアウト方法はどうでしょうかというお話。

PHP でテンプレートと言えば生の PHP でぺたっと書くか、Smarty やらといったテンプレートエンジンを利用するのが一般的だと思います。このテンプレート、デザイナさんから見ると嫌な存在ではないでしょうか?テンプレート毎に文法を覚えたり、対応したエディタを用意したり。せっかく覚えるならいろんな言語で通用する技術がいいですよね。XSLT もいいですが、ちょっとひねくれて XInclude を使っちゃいましょう。

ここでは、PHP で XInclude に触れてみたいと思います。まず、デザイナさんに一枚の XHTML を渡します。

Template.xhtml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xi="http://www.w3.org/2001/XInclude" xml:lang="ja-JPN">
    <head>
        <!-- この部分にヘッダを書いて下さいネ。 -->
        <!-- <link rel="stylesheet" type="text/css" href="" /> -->
        <!-- <script type="text/javascript" src=""></script> -->

        <xi:include href="Page.xhtml" xpointer="xmlns(xh=http://www.w3.org/1999/xhtml) xpointer(/xh:html/xh:head/*)">
            <xi:fallback>
                <!-- この部分は実行時にページ固有のヘッダに置き換えられます。 -->
                <title>デザイン中です</title>
            </xi:fallback>
        </xi:include>
    </head>
    
    <body>
        <xi:include href="Page.xhtml" xpointer="xmlns(xh=http://www.w3.org/1999/xhtml) xpointer(/xh:html/xh:body/*)">
            <xi:fallback>
                <!-- この部分は実行時にページ固有の本本に置き換えられます。 -->
                <!-- 本本はだいたい次の XHTML となります(CSS 確認用に使って下さいネ)。 -->
                <h1>本文</h1>
                <p>どうたらこうたら</p>
                <h2>概要</h2>
                <p>どんどこどんどん</p>
                <h2>以下略</h2>
                <p>...</p>
            </xi:fallback>
        </xi:include>
    </body>
</html>

neptune.png
海王星は太陽の周りを164年と288日と少しを掛けて一周するそうです。彼女の存在が初めて確認されたのは1846年9月23日。その日を海王星上の元日と仮定したら、今日は12月の20日辺り。宇宙人も師走だねぇ。

cof.jpgコーヒーゼリーをストローで食べようとして、ズ…ズズズ…ズチュルルルーっとやってるうちに親から食い物で遊ぶなと怒られた経験は、多くの、いいえ誰しもあると思います。遺伝子レベルで刻まれた行動と言ってもいいでしょう。そんな心の隙間を満たす素敵な一品がこれ。コーヒーゼリーがたっぷり入ったミルクコーヒー、なかなか喰わせてくれる飲み物です。

なかなか攻撃的な飲み物です
予め小さく砕いておいたコーヒーゼリーにミルクコーヒーを入れたような構造なのですが、飲み終える頃になると底のほうに残ってしまうゼリー達。そうなるとなんとかストローで救い上げたくなるのが人情でしょう。だけど、ストローの口径が10mmもあるのでちょっとやそっと吸い上げてもダメ。だんだん強く吸い上げていくあなた。そのうち、減圧され続けてきた咥内の気圧が急激に高まりを見せたかと思うないなや、ストローを駆け上ってくるゼリー達に気付くはずです。だけどその時にはもう彼等は気管まで進入しています。結果、人体の咳嗽反射によって押し戻された彼等の一部は食道へ、一部が鼻腔へ攻撃を仕掛けます。そしてその一部が鼻腔へ詰まる事に成功します。外部から観察されるその姿は、とても食後のコーヒーを楽しんでいるような、優雅なものではないはずです。もしもあなたが食後の一杯にこれを選ぶなら、戦いの覚悟を決めるべきです。もしもあなたの同伴が飲もうとするなら、始めにゼリーを取るか体裁をとるか、強く確認しておきましょう。税抜き210円でここまで緊張させられる飲み物は初めてです。ドトールコーヒー恐るべし。

URL に西暦が混じっている名前空間ってありますね。<html xmlns="http://www.w3.org/1998/xhtml" /> とか、<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" /> とか、<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" /> とか。この西暦は何を意味するんだろう?

最初はバージョニングのために西暦を使ってるのかと考えてみたけど、年単位で分類するのはとっても不自然。テクノロジー名が西暦より前に来ないのはもっと不自然(Microsoft だけは自然)。じゃじゃ、バージョンニングじゃないのか?…そもそもテクノロジーとは関係ないのかも。URI のルールかも知れない。よし RFC の確認だ。英語は読めないので日本語訳だ。Studying HTTP さんの RFC 3986 日本語訳 より…

7.1. 信頼性と整合性
URI が情報を取得するために一度使用されたからといって、将来において同じ情報がその URI によって取得可能であるだろうという保証はない。
また、将来においてその URI を通じて取得可能な情報が過去に取得されたそれと著しく同様であるだろうという保証も全くない。
URI 構文は、与えられるスキームやオーソリティがどのようにその名前空間を割り当てるか、あるいは時を経た後にどうそれを維持するかを束縛しない。
そのような保証は、名前空間や問題となっているリソースを制御している人 (達) からのみ得る事ができる。
特定の意味論がある特定の URI スキームのための全ての命名機関{naming authorities} に必要な場合、その URI スキームは、名前永続性のような、追加的意味論を定義する事ができる。

そかそか。URI は地球にお住まいの山田太郎さんまでは保証する、でも1582年に生きていた山田太郎さんかも知れないし、2015年の山田太郎さんかも、その辺りは君たちでヨロシクって事ですね。URL に使うドメインは時限付き登録制だから、未来永劫自分のものには出来ない。だから xmlns="http://www.w3.org/xhtml" とかしちゃうと、2451年ぐらいの別人 w3.org さんにとっては xhtml なんて知らないよな訳で困った事になる。そこで西暦をくっつける俺俺ルールで解決した事にしよう、という妥協の結果が http://www.w3.org/1998/xhtml なんでしょうか。うーん、憶測を出ないね…。

xxxnyann-tedbroiler.png
この テッドブロイラー様が
丸焼きに してくれるにゃ!
がががーーっ!

xxxnyann-seiza.png

定数のような振る舞いをする array やオブジェクトが必要になるケースとはどのような場面でしょうか。 例えば、あるキャラクタの性格を array へ定義しておきそれを参照するケースにて、第三者によって後付設定を付加されたり書き換えられてしまい、 キャラクタが作者の意図しない方向へ進んでしまう可能性がある場合です。

<?php

/**
 * プロフィールを定義します。ここ以外で変更しちゃダメ!
 * 
 * @type array
 */
$profile = array(
        'image' => 'xxxnyann-zukai.png',
        'nickname' => 'モチ',
        'favorite' => 'お団子',
        'hobby' => '散歩',
        'skill' => 'じゃんけん',
        'option' => '井伊直政当世具足',
    );

$profile['favorite'] = 'お魚、お肉'; // な、何するだァー!
$profile['option'] = 'しっぽ'; // な、何するだァー!

?>

<table summary="ひこにゃんのプロフィールです。">
    <caption>ズバリ!これがひこにゃんだ!</caption>
    <thead>
        <tr>
            <th>いめーじ</th>
            <th>ふぃーちゃー</th>
            <th>すぺっく</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td rowspan="5"><img src="<?php echo htmlspecialchars($profile['image']); ?>" width="120" height="160" /></td>
            <td>ひこにゃんマウス</td>
            <td><?php echo htmlspecialchars($profile['favorite']); ?>をおもむろにむさぼるぞ!</td>
        </tr>
        <tr>
            <td>ひこにゃんハンド</td>
            <td><?php echo htmlspecialchars($profile['skill']); ?>でどんな逆境も順境に!</td>
        </tr>
        <tr>
            <td>ひこにゃんレッグ</td>
            <td><?php echo htmlspecialchars($profile['hobby']); ?>で鍛えた足腰で傾斜角60度の坂でもぐいぐいのぼる!</td>
        </tr>
        <tr>
            <td>ひこにゃんオプション</td>
            <td><?php echo htmlspecialchars($profile['option']); ?>がとても魅力的だぞ!</td>
        </tr>
    </tbody>
</table>
profile.png

これを防ぐ手立てとして、要素を変更できない array が欲しくなります。残念ながら PHP には読み取り専用の配列は用意されていないので、自作する必要があります。

xxnyann.png2007年も残すところ一ヶ月を切り、PHP 4 の開発・メンテナンスと、築城400年祭と、商標使用期限の終了が迫っています。既に PHP 5 への移行は済んだと思われますが、この機会にクラスを定義したファイルの読み込み方法について見直してみましょう。

クラスを定義したファイルを1ファイル1クラスで保存している場合、PHP 4 から使用できる手段として、コードの先頭で require_once() を使用して読み込んでいました。使用するクラスの数だけ列挙が必要なため、オブジェクト同士の協調を図るコードを書く場合など、非常に多くの手間が掛かります。
例えば…

<?php
/**
 * クリスマス・イヴ未明からクリスマス終日にかけてひこにゃんが一緒に居てくれます。
 */

// require_once() からクラス定義ファイルを相対パスで読めるようにして。
set_include_path(get_include_path() . PATH_SEPARATOR . '/path/to/my/');

require_once 'My/DateTime.php';
require_once 'My/TimeSpan.php';
require_once 'My/Schedule.php';
require_once 'My/HikonyannPool.php';
require_once 'My/NakanohitoNadoInaiException.php';
require_once 'My/PoolOverflowException.php';
require_once 'My/TrademarkExpiredException.php';


// 私「2007-12-24T00:00:00Z から」
$when = new My_DateTime(2007, 12, 23, 15, 0, 0);
// 私「二日間ほど」
$howlong = new My_TimeSpan(2, 0, 0, 0);
// 私「借りたいの!」
$schedule = new My_Schedule($when, $howlong);

// 私「ダメ?」
try
{
    $hikonyann = HikonyannPool::borrow($schedule); 
    echo $hikonyann->letEnjoy();
    
    /****
            /i     iヽ
  ワーワー     ((/□\))
           ソ_∠ニ二ス  キャーキャー
      ヽ○ノ ∠シ,, ・ェ・ )ゝ
        |○ノ  (   ) ヾ○ノ
        へ|  ○ ∪∪    |
         /> /|ヽ      lヽ
           ∧ 
     ****/
}
// 市「ダメ(中の人などいない的に)」
catch (My_NakanohitoNadoInaiException $e) 
{
    echo 'ひこにゃんもクリスマスを楽しんでいます。';
}
// 市「ダメ(着ぐるみ数が限界的に)」
catch (My_PoolOverflowException $e)
{
    echo 'ひこにゃんは忙しいです。';
}
// 市「ダメ(登録商標的に)」
catch (My_TrademarkExpiredException $e)
{
    echo '尻尾をつけたのが不味かったか!?';
}

?>

この膨大な require_once にうんざりした PHP 5 は、解決手段としてオブジェクトのオートローディングを用意しました。未定義のクラスが使用された時点で、__autoload() がユーザー定義されていれば引数にクラス名を与えて呼び出され、クラスを定義する機会が与えられます。
例えば…