エンジニアブログ

エンジニアブログ
MT技術情報

変数名の罠

ぴろり上西 2011年05月28日

 Facebook 上の MT 関連コミュニティで次のような質問がありました。

<MTSetVarBlock name="folder-label">美しい日本語</MTSetVarBlock>
<MTSetVarBlock name="page-title">美しい日本語</MTSetVarBlock>
folder-label: <$MTGetVar name="folder-label"$>
page-title: <$MTGetVar name="page-title"$>
<MTIf name="folder-label" eq="$page-title">TRUE<MTElse>FALSE</MTIf>

 上記のようなテンプレートで変数比較が期待した動作にならない、というものです。質問された方は、変数値に日本語文字列が含まれていることが原因であると考えていらっしゃるようでしたが、これについて調べてみました。

 結論から言うと、変数値が日本語文字列であることとは関係なく、変数名が理由で期待した動作が行われていないことがその理由です。具体的には 5 行目の MTIf に渡されている like 引数が正しく変数展開されていないのです。
 確認のために 3 行目と 4 行目で変数にセットされた内容を出力していますが、ここではどちらも同じ値を出力します。しかし、その次の MTIf では、文字列比較に失敗します。

 理由は次の通りです。テンプレートタグのオプション値に $ から始まる文字列を指定すると、それを変数として解釈し、その変数の値が実際のオプション値として渡されます。この時、オプション値に渡された文字列をそのまま即値として解釈するか、変数として解釈するかの判定条件に原因があります。
 その判定を行っている処理は /lib/MT/Builder.pm の build 関数内にあり、オプション値が次の条件を満たす場合には変数として値が展開されます。

  • 1 文字目が $ で始まること
  • 2 文字目は英字またはアンダーバー(_)であること
  • 3 文字目以降がある場合、全て英数字またはアンダーバー(_)またはピリオドであること

 上記の条件を満たさない場合、渡された文字列は変数として解釈されず、そのままの値として渡されます。先のテンプレートでは、page-title という変数に使われているハイフン(-)が理由で、変数名として解釈されず変数が展開されなかったのでした。そのため、次のテンプレートは奇妙にも TRUE を返します。

<MTSetVarBlock name="folder-label">$page-title</MTSetVarBlock>
folder-label: <MTGetVar name="folder-label">
<MTIf name="folder-label" eq="$page-title">TRUE<MTElse>FALSE</MTIf>

 Facebook コミュニティであった質問の答えは「変数名にハイフンが含まれていて、期待した変数展開が行われていなかったため」ということで決着するのですが、変数名に関しては続きがあります。
 引数に渡された文字列が変数展開されるか否かの条件は先述の通りですが、引数の変数展開を考えないのであれば、変数名には全くの制限がありません。これは一般的なプログラミング言語では考えられないことです。例えば、次のようなテンプレートでも正しく動作してしまいます。

# 数字の変数名
<MTSetVar name="1" value="TEST STRING">
<MTGetVar name="1"> → TEST STRING

# 記号の変数名
<MTSetVar name="!#$%&'()-=^~" value="TEST STRING">
<MTGetVar name="!#$%&'()-=^~"> → TEST STRING

# 空白の変数名
# 空白の数の違いで別の変数扱いになる!
<MTSetVar name="   " value="TEST STRING">
<MTGetVar name=" ">
<MTGetVar name="  ">
<MTGetVar name="   "> → TEST STRING

# 空白を含む変数名
# "abc" と " abc " は別変数扱いになる!
<MTSetVar name=" abc " value="TEST STRING">
<MTGetVar name="abc">
<MTGetVar name=" abc "> → TEST STRING
# でも英字の大文字小文字は区別しないという...
<MTGetVar name=" aBc "> → TEST STRING

 MT 変数名は、プログラム内部でハッシュ変数のキー文字列として使われていて、実際のところMT で指定できないようなどんな値でもキー名=変数名に使うことができます。

まとめ

MT で使える変数名について

  • 一般的なプログラミング言語にあるような変数の命名規則は存在しない
  • 数字、記号、空白などのあらゆる文字を任意の順列で使用できる
  • 空白も文字として扱われるので、"abc" と " abc " は別変数になる
  • テンプレートタグなどの引数に $ から始まる文字列を指定すると変数展開されるが、その時、変数として解釈されるためには変数名に条件がある
  • なので、あまり変態的な変数名を用いず、英数字から成る平凡な変数名にしておくと、変な仕様に悩まされずに済む