Idea4

Top > PluginDev > Class > Idea4

(似非)シングルトンコピー版

Table of Contents

クラス化

1つのインスタンスを global 変数として使いまわします。 使用する際に、インスタンスの初期化をするをするのではなく、発想の転換で、インスタンスのコピーをとっておき、初期化の手間を省きます。

概略

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

詳細

<?php
class PluginXxx
{
    // define()していた設定用定数やグローバル変数など
    var $conf;
    // インスタンス変数
    var $var;
    function PluginXxx()
    {
        // plugin_xxx_init()
        // define()していた設定用定数やグローバル変数などの初期化
        // インスタンス変数の初期化
    }
    function convert()
    {
        // function_xxx_convert()
    }
    function inline()
    {
        // function_xxx_inline()
    }
    function action()
    {
        // function_xxx_action()
    }
}

if (! function_exists('create_clone')) {
    function create_clone($object) {
        if (version_compare(phpversion(), '5.0') < 0) {
            return $object;
        } else {
            return @clone($object);
        }
    }
}
function plugin_xxx_init()
{
    global $plugin_xxx;
    $plugin_xxx = new PluginXxx();
}
function plugin_xxx_convert()
{
    global $plugin_xxx; $clone_plugin_xxx = create_clone($plugin_xxx);
    $args = func_get_args();
    return call_user_func_array(array(&$clone_plugin_xxx, 'convert'), $args);
}
function plugin_xxx_inline()
{
    global $plugin_xxx; $clone_plugin_xxx = create_clone($plugin_xxx);
    $args = func_get_args();
    return call_user_func_array(array(&$clone_plugin_xxx, 'inline'), $args);
}
function plugin_xxx_action()
{
    global $plugin_xxx; $clone_plugin_xxx = create_clone($plugin_xxx);
    return call_user_func(array(&$clone_plugin_xxx, 'action'));
}
?>

ユーザ設定について考える(Plus!)

Pukiwiki Plus! にあるユーザ設定機能をどのように使えるかについて考えます。 PukiWiki Plus! には、プラグインファイルが読み込まれる直前に、init/プラグイン名.ini.php というファイルを読み込む、という機能があり、これをプラグインの初期値設定用に使用できます。プラグインアップデートの際にプラグインファイルを再度書き換えせずに済むので親切です。

init/プラグイン名.ini.php 中の設定が勝るようにするために、plugin_xxx_init 関数に

function plugin_xxx_init()
{
    global $plugin_xxx;
    if (! isset($plugin_xxx)) {
        $plugin_xxx = new PluginXxx();
    }
}

のように ! isset の if 文を追加しておきます。

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

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

もしくは

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

関数のオーバーライドまでも可能です。

ちなみに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 を行う場合は、関数実行後や、プラグイン実行後のインスタンス変数の値を参照したいものです。 そのため、例えば convert ならば

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

のように $clone_plugin_xxx を global 変数化することによって、UnitTest のコードからインスタンスにアクセスでき、 インスタンス変数の値を参照することができるようになります。

まとめ

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

<?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()
    {
        // plugin_xxx_init()
        // define()していた定数やその他のグローバル変数などの初期化も必要があればここで行う
    }
    function convert()
    {
        // function_xxx_convert()
    }
    function inline()
    {
        // function_xxx_inline()
    }
    function action()
    {
        // function_xxx_action()
    }
}

if (! function_exists('create_clone')) {
    function create_clone($object) {
        if (version_compare(phpversion(), '5.0') < 0) {
            return $object;
        } else {
            return @clone($object);
        }
    }
}
function plugin_xxx_init()
{
    global $plugin_xxx;
    if (! isset($plugin_xxx)) { // for init/xxx.ini.php
        $plugin_xxx = new PluginXxx();
    }
}
function plugin_xxx_convert()
{
    global $plugin_xxx, $clone_plugin_xxx;
    $clone_plugin_xxx = create_clone($plugin_xxx);
    $args = func_get_args();
    return call_user_func_array(array(&$clone_plugin_xxx, 'convert'), $args);
}
function plugin_xxx_inline()
{
    global $plugin_xxx, $clone_plugin_xxx;
    $clone_plugin_xxx = create_clone($plugin_xxx);
    $args = func_get_args();
    return call_user_func_array(array(&$clone_plugin_xxx, 'inline'), $args);
}
function plugin_xxx_action()
{
    global $plugin_xxx, $clone_plugin_xxx;
    $clone_plugin_xxx = create_clone($plugin_xxx);
    return call_user_func(array(&$clone_plugin_xxx, 'action'));
}
?>