Idea2

Top > PluginDev > Class > Idea2

クラス変数版

Table of Contents

クラス化

global 変数や定数の代わりをクラス変数で行います。 PHP4 ではクラス変数が使用できませんが、 クラス変数の「ようなもの」を定義するテクニックを使用で回避します。

概略

class PluginXxx {
  static $...             /* define()していた設定用定数やグローバル変数など */
  var $...                /* インスタンス変数     */
  function PluginXxx()  { /* インスタンスの初期化 */ }
  function action()     { /* plugin_xxx_action()  */ }
  function convert()    { /* plugin_xxx_convert() */ }
  function inline()     { /* plugin_xxx_inline()  */ }

ただし、PHP4 ではこのように static を使用できないので、クラス変数の「ようなもの」を定義するテクニックを使用する。

詳細

<?php
class PluginXxx
{
    /* define()していた設定用定数やグローバル変数など */
    var $conf; 
    /* メンバ変数     */
    var $var;
    function PluginXxx()
    {
        // define()していた設定用定数やグローバル変数など
        // PHP4 でクラス変数の「ようなもの」を定義するテクニックを使用する。
        static $conf = array(
        );
        $this->conf = & $conf;

        // インスタンスの初期化。そもそもメンバ変数を作る必要がない場合も多い。
        $this->var = ...;
    }
    function convert()
    {
        // function_xxx_convert()
    }
    function inline()
    {
        // function_xxx_inline()
    }
    function action()
    {
        // function_xxx_action()
    }
}

function plugin_xxx_convert()
{
    $plugin_xxx = new PluginXxx();
    $args = func_get_args();
    return call_user_func_array(array(&$plugin_xxx, 'convert'), $args);
}
function plugin_xxx_inline()
{
    $plugin_xxx = new PluginXxx();
    $args = func_get_args();
    return call_user_func_array(array(&$plugin_xxx, 'inline'), $args);
}
function plugin_xxx_action()
{
    $plugin_xxx = new PluginXxx();
    return $plugin_xxx->action();
}
?>

ユーザ設定(Plus!)

Pukiwiki Plus! にあるユーザ設定機能をどのように使うか。プラグインファイルが読み込まれる前に読み込まれます。

init/xxx.ini.php では以下のように初期設定を行えます。

<?php
exist_plugin('xxx'); // require_once
$plugin_xxx = new PluginXxx();
$plugin_xxx->conf['key'] = ....;
?>

しかし、このままでは (似非)シングルトン版 ではできた、関数のオーバーライドができないので劣っている気がします。そこで plugin_xxx_init 関数に工夫をし、プラグイン関数を次のように実行します。

function plugin_xxx_init()
{
    global $plugin_xxx_class;
    if (class_exists('PluginXxxUser')) {
        $plugin_xxx_class = 'PluginXxxUser';
    } else {
        $plugin_xxx_class = 'PluginXxx';
    }
}
function plugin_xxx_convert()
{
    global $plugin_xxx_class;
    $plugin_xxx = new $plugin_xxx_class();
    $args = func_get_args();
    return call_user_func_array(array(&$plugin_xxx, 'convert'), $args);
}

init/xxx.ini.php では以下のように関数のオーバーライドができるようになります。 PluginXxxUser のように、対策された名前限定になりますが、大した問題ではないでしょう。

<?php
exist_plugin('xxx'); // require_once
class PluginXxxUser extends PluginXxx
{
    function PluginXxxUser()
    {
        parent::PluginXxx();
        $this->conf = '.....';
    }
}
?>

ちなみにPukiWiki 本家のほうでもこの機能に対応するには、プラグインファイルの先頭に

if (! defined('INIT_DIR')) // if not Plus!
    if (file_exists(DATA_HOME . 'init/xxx.ini.php'))
        include_once(DATA_HOME . 'init/xxx.ini.php');

を追加しておけば可能です。

UnitTest について考える

UnitTestForPlugins 参照。

UnitTest を行う場合は、関数実行後や、プラグイン実行後のインスタンス変数の値を参照したいものです。 なのでインスタンスをグローバル変数として定義してしておきます。

function plugin_xxx_convert()
{
    global $plugin_xxx;
    $plugin_xxx = new PluginXxx();
    $args = func_get_args();
    return call_user_func_array(array(&$plugin_xxx, 'convert'), $args);
}

また、UnitTest 用ユーザ定義をしたい場合も考えられるので、

function plugin_xxx_init()
{
    global $plugin_xxx_class;
    if (class_exists('PluginXxxUnitTest')) {
        $plugin_xxx_class = 'PluginXxxUnitTest';
    } elseif (class_exists('PluginXxxUser')) {
        $plugin_xxx_class = 'PluginXxxUser';
    } else {
        $plugin_xxx_class = 'PluginXxx';
    }
}

と用意しておくことにします。

まとめ

統合してみると次のようなコードになります。

<?php
if (! defined('INIT_DIR')) // if not Plus!
    if (file_exists(DATA_HOME . 'init/xxx.ini.php'))
        include_once(DATA_HOME . 'init/xxx.ini.php');

class PluginXxx
{
    /* define()していた設定用定数やグローバル変数など */
    var $conf; 
    /* インスタンス変数     */
    var $var;
    function PluginXxx()
    {
        // define()していた設定用定数やグローバル変数など
        // PHP4 でクラス変数の「ようなもの」を定義するテクニックを使用する。
        static $conf = array(
            // ....
        );
        /* static 宣言で直接代入できない場合 (関数を呼ぶ必要があるなど) は、
        static $conf = array(); if (empty($conf)) { $conf = array(
            // ....
        );}
        と書くと良いかもしれない。*/
        $this->conf = & $conf;

        // インスタンスの初期化
        $this->var = ...;
    }
    function convert()
    {
        // function_xxx_convert()
    }
    function inline()
    {
        // function_xxx_inline()
    }
    function action()
    {
        // function_xxx_action()
    }
}

function plugin_xxx_init()
{
    global $plugin_xxx_class;
    if (class_exists('PluginXxxUnitTest')) {
        $plugin_xxx_class = 'PluginXxxUnitTest';
    } elseif (class_exists('PluginXxxUser')) {
        $plugin_xxx_class = 'PluginXxxUser';
    } else {
        $plugin_xxx_class = 'PluginXxx';
    }
}
function plugin_xxx_convert()
{
    global $plugin_xx, $plugin_xxx_class;
    $plugin_xxx = new $plugin_xxx_class();
    $args = func_get_args();
    return call_user_func_array(array(&$plugin_xxx, 'convert'), $args);
}
function plugin_xxx_inline()
{
    global $plugin_xx, $plugin_xxx_class;
    $plugin_xxx = new $plugin_xxx_class();
    $args = func_get_args();
    return call_user_func_array(array(&$plugin_xxx, 'inline'), $args);
}
function plugin_xxx_action()
{
    global $plugin_xx, $plugin_xxx_class;
    $plugin_xxx = new $plugin_xxx_class();
    $args = func_get_args();
    return $plugin_xxx->action();
}
?>