Php 使脚本可插入

Php 使脚本可插入,php,Php,我正在编写一个脚本,我需要使它可插入。现在,我附带的语法应该对我有用,就是让它使用类。例如,为了创建一个在到达某个点(钩子)时运行的新插件,您需要声明一个新类。我不确定的是如何在该语法中指定钩子,因此我正在寻找建议 语法示例: <?php class ScriptPlugin { function runPlugin() {} // would be run when the time has to come to execute this plugin } ?> 另外

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

语法示例:

<?php
class ScriptPlugin
{
    function runPlugin() {} // would be run when the time has to come to execute this plugin
}
?>


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

我将创建一个基本抽象类,其中包含所有可能被调用的钩子的函数

abstract class Plugin {
    abstract function yourHook();
}
所有插件类都应该继承这个基类,并用它们自己的基类重写这些基类函数

class SomePlugin extends Plugin {
    function yourHook() {
        echo 'yourHook() Called!';
    }
}
现在,当程序运行时,您需要找到所有要包含的插件文件,并以某种方式将它们放入数组中,例如
$plugins
。见本文:

(来自卡斯滕)

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

使每个插件文件的顶行如下(在类之前):

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

foreach ($plugins as $plugin) {
    $plugin->yourHook();
}

作为替代,它可能更适合在您的案例中使用。您应该决定哪种方法最适合您的应用程序。

假设一个插件如下:

class NewsPlugin extends Plugin
{
  function onCreate($title)
  {
    # Do some stuff
  }
}
然后,当您创建新闻时,只需在所有注册的插件上调用onCreate即可。

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

我想到的另一件事是PHP中的回调。我突然想到了一个问题。它显示了基于回调的钩子

观察者模式运行时间有点短,因为使用钩子时,您通常希望提供参数和返回值之类的内容。使用回调的链接答案也没有这个功能,因此我编写了一个小的
Hooks
示例类,它为注册的回调提供命名的Hooks/events,并提供一种注册自己类的方法,例如插件

这个想法非常基本:

  • 钩子有一个名称和零个或多个回调
  • 所有挂钩都在
    hooks
    类中管理
  • 主代码通过调用
    hooks
    对象上的函数来调用hooks
  • 插件(和其他类)可以注册自己的回调,这是在
    Registerable
    接口的帮助下完成的
一些带有一个插件和两个挂钩的示例代码:

<?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");
但是,您可以自己创建一个插件基类,例如实现
register
函数,并自动注册具有特定docblock标记或函数名称的函数

class MyNewPlugin extends PluginSuper
{
    /**
     * @hook postPublished
     */
    public function justAnotherFunction() {}

    public hookPostPublished() {}
}

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

您没有在问题中添加代码,这些代码实际上会显示您所询问的语法。请添加代码,否则就很难说了。这就是我要实现的语法。但是,我在查找所有插件时遇到了问题。我通常把它们都放在一个名为
plugins
的目录中,并使用
glob
将它们全部放在我的标题中。它们都扩展了相同的基类。如果我可以在Plugin类中使用a _construct()方法,那么当创建一个新实例并基于该类时,它应该以某种方式将$this变量传递到plugins数组中,你觉得怎么样?当然,这是可行的,但是$plugins应该是一个全局变量,并且仍然需要构造插件。我明白了。此外,即使我在类插件中添加了_construct(),我仍然无法运行全局插件函数,比如说“runPlugin()”之类的,可以吗?一切都很好。这正是我想要实现的。但是,我失败的是,我无法识别插件文件中的类的名称是什么?我不认为要求插件文件与类具有相同的名称是好的,这样才能知道类实际具有的名称,对吗?我想有一个类似的,但不是相同的东西。无论如何,这已经足够好了,但我会首先尝试实现我想要做的事情。如果我不满意,我将使用这种方法。我想谢谢你@用户726049,看看
\uu autoload()
:这正是我想要的工作方式。我尝试实现自动注册函数的类,该类应该在插件启动时运行,但没有成功。不幸的是,我对OOP知之甚少:(这个插件需要在一个钩子上注册它的函数。你可能想在我答案的末尾添加你的代码,这样我就可以看一下了。
class NewsPlugin extends Plugin
{
  function onCreate($title)
  {
    # Do some stuff
  }
}
<?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");
$hooks->attach('hookName', function() {echo "Hook was called\n";});
class MyNewPlugin extends PluginSuper
{
    /**
     * @hook postPublished
     */
    public function justAnotherFunction() {}

    public hookPostPublished() {}
}