コード

スキン変数からスキンタグへ

2010年1月11日

Nucleusでは、<%blog%>などの表記を『スキン変数』と呼んでいて、Jeansでもそのように扱ってきました。これがどのような経緯で変数(variables)と呼ばれるようになったのかよく知りませんが、個人的には、これを変数と呼ぶのにどうも違和感があります。

これはむしろタグなのではないかと思うし、実際、WordPressなどの別のツールで似た機能をするものはタグと呼ばれています。そこで、Jeansでもこれをタグと呼ぶことにしました。つまり、Nucleusにおけるスキン変数は、Jeansではタグもしくはスキンタグということになります。Jeansではテンプレートもスキンも同じなので、Nucleusのテンプレート変数に相当するものも、タグもしくはスキンタグで、多くの場合<%data%>タグがこれに相当します。

この名称変更に伴い、いままでスキンタグ(スキン変数)を実装するためのメソッドを

public static function var_xxx()

としていたところ、

public static function tag_xxx()

に変更しました(リビジョン79)。

この関連で、Jeansのコードに関してひとつ考察しておきたいことがあります。今のところ、『public static function tag_xxx()』とすれば、『xxx』がスキンタグとして有効になります。この部分を少し変更し、スキンタグとして有効にするかどうかにもう一段チェックルーチンを入れることを、考えてみました。これは、Nucleusでは、ITEMACTIONS::getDefinedActions()などに相当する部分です。次のように記述するイメージです。

class blog extends jeans {
    public static function tags() {
        return array('narrowby','blog');
    }
    public static function tag_narrowby() {

    }
    public static function tag_blog() {

    }
}

つまり、blog::tags()で返されたものだけが、blogクラスのスキンタグとして有効になります。こうすることのメリットは、権限管理が容易になることです。上記の例では、blog::tags()内でメンバーの権限をチェックし、使用を許可するメソッドを、権限の異なるメンバーごとに区別して返すというような記述が可能です。blogクラスではこのようなことは必要ありませんが、管理関連のクラス(admin_xxxx)では、このようなやり方が有効です。現在のコードでは、init()メソッドで権限をチェックし、ユーザーが実行権限を持たない場合はプロセスを停止(exitの実行)するようにしています。上記のようなやり方を採用すると、エラーメッセージなども正しく表示できたり(ちゃんと、</html>タグがある)、メソッドごとにアクセス可能な権限が異なるようなケースでも、コードを容易に書けて管理もしやすいように思います。

デメリットとしては、ライブラリ用のクラスを書くことの敷居が高くなることです。tag_xxx()を定義するだけでスキンタグとして有効になる現在の仕様の方が分かりやすく、また、このことでバグに悩まされることもありません(NucleusのgetDefinedActions()には何度か悩んだことがあります)。加えて、『static public function』とパブリック宣言しているにもかかわらず、クラスメソッドがタグとして有効ではないというようなケースがあることは、PHPコードとJeansの挙動の整合性を考えてみても、美しくありませんし、このことが原因のセキュリティーホールを生み出す可能性も有ります。

今のところ、メリットとデメリットを天秤にかけてみると、デメリットの方が大きいように感じています。このことは、PHP 5.3に移行するまでの課題とします。5.3では、__callstaticというマジックメソッドが使えるので、例えば次のように書くことが可能です。

class blog extends jeans {
    public static function __callstatic($name,$args) {
        switch ($name) {
            case 'tag_narrowby': case 'tag_blog': 
                return call_user_func_array(array('self',$name),$args);
            default:
                return;
        }
    }
    private static function tag_narrowby() {

    }
    private static function tag_blog() {

    }
}

この例では、いかなるケースでもtag_narrowbyとtag_blogが有効になっているので意味ありませんが、少し書き換えるだけで、メンバーの権限ごとにメソッドの呼び出しを許可したり拒否したりするのが簡単にできます。しかも、本体のメソッドはプライベート宣言しているので、コードのどこかで書き間違えが有っても絶対に直接呼ばれることはありません。

ちなみに、上記のコードでは、method_exists('blog','tag_blog')の戻り値は、PHP 5.2, 5.3 の両方で、trueです。is_callable(array('blog','tag_blog'))の戻り値は、5.2ではfalse、5.3ではtrueになります。method_exists('blog','dummy')の戻り値は、両方ともfalseです。これらの結果からわかることは、medthod_existsは、プライベートやプロテクテッドなどのアクセス不可能なメソッドでもtrueを返すこと、PHP 5.3では、__callstaticを宣言すると、いかなるメソッドに関しても、is_callableでtrueを返すことです。後者の仕様は、PHPの今後のバージョンで改善して欲しいものです(__callable()の実装?)。


追加情報
<?php

echo method_exists('test','func_test')?"func_test exists.\n":"func_test does not exist.\n";
echo method_exists('test','func_dummy')?"func_dummy exists.\n":"func_dummy does not exist.\n";
echo is_callable(array('test','func_test'))?"func_test is callable.\n":"func_test is not callable.\n";
echo is_callable(array('test','func_dummy'))?"func_dummy is callable.\n":"func_dummy is not callable.\n";

test::func_test();

class test {
	static protected function func_test(){
		echo __CLASS__.'::'.__FUNCTION__."\n";
	}
	static public function __callstatic($name,$args){
		echo __CLASS__.'::'.__FUNCTION__."($name,$args)\n";
	}
}

PHP 5.2での実行結果
func_test exists.
func_dummy does not exist.
func_test is not callable.
func_dummy is not callable.

Fatal error: Call to protected method test::func_test()

PHP 5.3での実行結果
func_test exists.
func_dummy does not exist.
func_test is callable.
func_dummy is callable.
test::__callstatic(func_test,Array)


追記
スキンタグでなく、アクションの方は、core::action()メソッド内で__callstaticを直接呼び出すことで、PHP 5.2でも上記のような記述ができそうです。権限については、アクションの方での管理が主なので、これは考えてみる価値があると思います。スキンタグでの利用は、5.3を待ったほうが良さそうです。

コメント

コメントはありません

コメント送信