首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使脚本可插件化

使脚本可插件化
EN

Stack Overflow用户
提问于 2011-12-26 23:33:04
回答 3查看 385关注 0票数 5

我正在编写一个脚本,我需要让它成为可插件。现在,我提供的语法应该适用于我,就是让它使用类。例如,为了创建一个在到达某个点(钩子)时运行的新插件,您需要声明一个新类。我不确定的是如何在该语法中指定钩子,所以我正在寻找建议。

语法示例:

代码语言:javascript
复制
<?php
class ScriptPlugin
{
    function runPlugin() {} // would be run when the time has to come to execute this plugin
}
?>

此外,如果语法不起作用,如果你们能给我一个很好的语法示例,那就太好了。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-12-27 01:34:53

脑海中浮现出观察者模式。插件会自行注册,并在钩子被调用时收到通知。

想到的另一件事是PHP中的回调。有一个带有an answersimilar question already出现在我的脑海中。它显示了基于回调的钩子。

观察者模式运行得有点短,因为使用钩子通常需要提供参数和返回值等内容。使用回调的链接答案也没有这个,所以我写了一个小的Hooks示例类,它为注册的回调提供了命名钩子/事件,并提供了一种注册自己的类的方法,例如插件。

这个想法很基本:

  • 挂接有一个名称和零个或多个附加的回调。
  • 所有挂接都在Hooks类中进行管理。
  • 通过调用Hooks挂接上的函数来调用挂接的主代码(和其他类)可以注册它们自己的回调,这是在Registerable接口的帮助下完成的。<代码>H214<代码>F215

一些带有一个插件和两个钩子的示例代码:

代码语言:javascript
复制
<?php
Namespace Addon;

class Hooks
{
    private $hooks = array();
    private $arguments;
    private $name;
    private $return;
    public function __call($name, array $arguments)
    {
        $name = (string) $name;
        $this->name = $name;
        $this->arguments = $arguments;
        $this->return  = NULL;
        foreach($this->getHooks($name) as $hook)
        {
            $this->return = call_user_func($hook, $this);
        }
        return $this->return;
    }
    public function getHooks($name)
    {
        return isset($this->hooks[$name]) ? $this->hooks[$name] : array();
    }
    public function getArguments()
    {
        return $this->arguments;
    }
    public function getName()
    {
        return $this->name;
    }
    public function getReturn()
    {
        return $this->return;
    }
    public function setReturn($return)
    {
        $this->return = $return;
    }
    public function attach($name, $callback)
    {
        $this->hooks[(string) $name][] = $callback;
    }
    public function register(Registerable $plugin)
    {
        $plugin->register($this);
    }
}

interface Registerable
{
    public function register(Hooks $hooks);
}

class MyPlugin implements Registerable
{
    public function register(Hooks $hooks)
    {
        $hooks->attach('postPublished', array($this, 'postPublished'));
        $hooks->attach('postDisplayFilter', array($this, 'filterToUpper'));
    }
    public function postPublished()
    {
        echo "MyPlugin: postPublished.\n";
    }
    public function filterToUpper(Hooks $context)
    {
        list($post) = $context->getArguments();
        return strtoupper($post);
    }
}

$hooks = new Hooks();

$plugin = new MyPlugin();
$hooks->register($plugin);  

$hooks->postPublished();

echo $hooks->postDisplayFilter("Some post text\n");

我这样做是为了防止每个插件都必须有一个具体的基类,因为它想要使用钩子。此外,一切都可以注册钩子,唯一需要的是一个回调。例如,一个匿名函数:

代码语言:javascript
复制
$hooks->attach('hookName', function() {echo "Hook was called\n";});

但是,您可以创建自己的插件基类,例如实现register函数,并自动注册具有特定docblock标记或函数名称的函数

代码语言:javascript
复制
class MyNewPlugin extends PluginSuper
{
    /**
     * @hook postPublished
     */
    public function justAnotherFunction() {}

    public hookPostPublished() {}
}

超类可以利用Reflection在运行时添加钩子。然而,反射可能会减慢速度,并可能使调试变得更加困难。

票数 3
EN

Stack Overflow用户

发布于 2011-12-26 23:37:49

我会为所有可能被调用的钩子创建一个带有函数的抽象基类。

代码语言:javascript
复制
abstract class Plugin {
    abstract function yourHook();
}

所有的插件类都应该继承这个基类,并用它们自己的函数覆盖这些基函数。

代码语言:javascript
复制
class SomePlugin extends Plugin {
    function yourHook() {
        echo 'yourHook() Called!';
    }
}

现在,当您的程序运行时,您需要找到所有要包含的插件文件,并以某种方式将它们放入一个数组中,例如$plugins。请参阅本文:https://stackoverflow.com/a/599694/362536

代码语言:javascript
复制
foreach (glob("classes/*.php") as $filename)
{
    include $filename;
}

(摘自Karsten)

定义一个可以从任何地方访问的函数,例如registerPlugin()

代码语言:javascript
复制
function registerPlugin($classname) {
    $plugins[] = new $classname();
}

让每个插件文件的顶行像这样(在类之前):

代码语言:javascript
复制
registerPlugin('SomePlugin');

如果这样做,您将在$plugins中拥有一个数组,其中包含每个插件的实例。在适当的时候,你可以这样做:

代码语言:javascript
复制
foreach ($plugins as $plugin) {
    $plugin->yourHook();
}

作为另一种选择,在您的情况下使用interfaces可能更合适。您应该决定哪种方法最适合您的应用程序。

票数 0
EN

Stack Overflow用户

发布于 2011-12-26 23:39:20

假设一个插件是这样的:

代码语言:javascript
复制
class NewsPlugin extends Plugin
{
  function onCreate($title)
  {
    # Do some stuff
  }
}

然后,当你创建一条新闻时,你可以在所有注册的插件上调用onCreate。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8637054

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档