是否应该将所有插件封装在Class中?


Answers:


24

开发插件时,应将功能分组到一个类中以避免命名空间冲突?

是的,但这只是次要参数之一。实际上,这不是OOAD中的类的“真实”本质。

使用类是否会增加PHP的性能开销?

不,值得注意的是。与实际的语言功能相比,不良的设计和/或不良的书面代码或过早的优化会带来更多的性能问题。

如果对性能有影响,是否应该在函数名前面加上前缀?

如所写,不会影响性能。与具有更多行代码但不会强迫您做坏事的好的书面代码相比,坏的书面代码对性能的影响更大。


底线:

您可以为插件使用不同的类。您可以使用它们来拥有某种名称空间,并“仅”将它们用于全局函数。其中最直接的形式是静态类函数,下面的代码示例首先显示全局函数,然后显示全局静态类函数:

/* global function */
function myplug_hook()
{
}

add_filter('the_hook', 'myplug_hook');


/* global static function */
class myplug
{
    public static function hook()
    {
    }
}

add_filter('the_hook', 'myplug::hook');

这只是一个小例子,显示您需要为单个钩子键入更多内容。此外,它还显示了命名空间的工作原理:您可以更轻松地替换单个类名,以重命名所有静态函数,然后搜索和替换myplug::myplug_因为误报可能会更难。但是最后并没有太大的区别。

关键是:静态类函数Docs全局函数Docs相比并没有太多其他意义。

这个示例也显示了:Namespacing很好,但是使用worpdress时,namespacing停止使用钩子:回调函数经过了强化编码,因此使用类(在base-name中,一个地方放置classname)命名空间的好处不大。当您使用wordpress插入代码来获取钩子名称时,此方法会有所帮助。

真正的好处始于使用实际的类实例和非静态函数。这样的好处是您可以开始使用OO原理,并且可以简化代码。静态类函数比实际解决方案更多的是问题。

然后,不仅是语法糖。

关键是:做一些有助于您编写易于处理和维护的代码的事情。不要高估性能,这是一个常见错误。更重要的是,您编写的代码易于阅读和理解,可以满足您的需求。在以下情况下,以下问题也许对更大的了解很有帮助:Multiple Custom Metabox Help

我什至对较小的插件也有一种常用的方法是利用静态帮助器函数实例化插件,然后其余的驻留在插件实例中。这有助于封装主要的插件逻辑,并通过使用钩子进行命名间隔以及在钩子之间重新使用私有成员(这是标准全局函数无法实现的)而受益。以下代码示例显示了该模式:

<?php
/** Plugin Headers ... */

return MyPlugin::bootstrap(); 

class MyPlugin
{
    /** @var MyPlugin */
    static $instance;
    static public function bootstrap() {
        if (NULL === self::$instance) {
            self::$instance = new __CLASS__;
        }
        return self::$instance;
    }
    # ...
}

这是我用于基本插件文件的常见模式。插件类一方面代表了wordpress的插件,另一方面,它允许开始为自己的代码使用面向对象的范例,甚至可以完全面向对象(但不必如此)。它是一种控制器,可以将整个wordpress API作为请求进行接口。

如示例所示,将创建插件的实例。这使您可以利用诸如Constructor Docs__construct)之类的已知公共资源来初始化实际的插件:

# ...
class MyPlugin
{
    # ...
    public function __construct()
    {
        add_filter('the_hook', array($this, 'hook'));
    }

    public function hook()
    {
    }
    # ...
}

在钩子注册时,此插件对象已从其设计中受益:您已停止将实际的钩子函数硬编码为具体的插件classname。这是可能的,因为该类已绑定到回调的对象实例。听起来很复杂,只是说:$this 插件。可以在钩子回调中使用,将注册类方法与钩子回调进行比较。

这种模式可以简化与wordpress的交互:注入被简化为钩子的名称以及它们提供的数据。然后,您可以开始直接在此插件类中实现或对它重构您的实现,以便仅将代码放到为针对wordpress定义插件接口的最低限度的插件类中,而将通用逻辑放在一旁。这是乐趣开始的地方,很可能是每个插件作者希望长期实现的目标。

因此,请勿使用worpdress进行编程,而应反对。由于worpdress具有相当大的灵活性,因此没有通用或易于描述的程序接口。一个基本的插件类可以担当此角色,从而为您自己的代码提供更大的灵活性,这将使代码更简单,性能更好。

因此,名称间隔不仅有好处。我能给出的最佳建议是:尝试一下。您不会放松太多,只有发现新事物。

在您通过对Wordpress进行了更多主要更新同时保持插件兼容之后,您很可能会注意到差异。

警告:如果您的插件直接与wordpress集成以完成工作,则使用一个或两个公共功能可能更适合您。为工作选择合适的工具。


1
如果静态类函数与全局函数确实没有什么不同,并且您的目标是防止命名空间冲突,那么我真的还不了解(现在)切换为类编写插件的必要性。另外,我对您的助手引导功能感到困惑。为什么不只将新对象声明为$ new_object = new MyClass();?
AlxVallejo 2012年

@AlxVallejo:单独命名空间并没有真正的必要(正如我在回答中所写,静态类方法与全局函数几乎相同)。因此,您可以自己命名(这是PHP 5.3之前的命名空间)。因此,您注意到这完全正确。与静态引导程序功能类似:从技术上讲,这不是必需的,也可以简单地return $myPlugin = new MyPlugin(); 做到这一点。但是,从更大的角度来看,一个简单的新词可能还不够,请比较WordPress插件:如何避免“紧密耦合”?
hakre 2013年

9

类VS功能集


性能

常规: Afaik,类和函数集之间的“性能”没有区别。

详情:

  • 如果您质疑function_exists()vs. class_exists()与通常有很大的不同(wp核心中有〜1.800(?))和类(wp核心中有〜100(?))。因此,使事物“可插入”并因此质疑其存在执行时间的差异。
  • 与函数集相比,类提供了一个很大的优势:您可以更轻松地避免在不需要它的请求上调用它,然后再使用函数。您只需要对类进行条件检查,而不必对每个函数进行条件检查。因此,如果您不需要在每次页面加载时都使用它,并且可以避免调用大量的if / else语句,则该函数“性能会更好”。

建筑-工作原理:

函数集:通常,函数在您调用它的行中执行。因此,每次调用某个东西时,如果必须多次调用它,就必须重新编写一次。

上课:上课有不同的方法。最接近功能集的类是“ factory”类(Wikipedia / google)。Imo它与一组函数几乎相同,但是封装在一个类中。但是也有其他“类型”的类。例如,您可以编写一个抽象类或一个父类类,然后再扩展一个子类。在一个真实的示例中:假设您有一个构建一些静态文本字段的类。在您的__construct()函数中,您有一组场景,例如“ left_column”,“ right_column”和“ footer_field”。然后调用类似$text_field = new TextFieldClass();实例化该类的内容。然后您只需致电$text_field->add( $case => 'left_column', 'case' => 'foo text' );$text_field->add( $case => 'footer_field', 'case' => 'bar text' );。这样,当实例化该类时,所有条件语句和其他条件语句都已执行,并且在构建文本字段时仅会调用两个类函数。在这种情况下,您可以节省几毫秒的执行时间。


个人想法

如果您明智地编写类,那么在性能方面将有次要的优势。但是您将有一个组织良好的结构来进行工作。到目前为止,没有什么壮观的。但是,如果您考虑以下插件中的类和函数的“拆分”用例,那么您将得到我的最终结论:类是内部的,函数是API。只要您仅通过可公开使用的函数(然后调用类或类函数)提供API,您就可以继续开发插件。您可以自由地更改内部结构,甚至可以更改插件的可能性,而不会随时随地影响用户。

例:

// construction of object
if ( ! class_exists( 'WPSE_HelloWorld' ) )
{

class WPSE_HelloWorld
{
    function __construct( $args = array( 'text', 'html', 'echo' ) )
    {
        // call your object building procedures here
        $this->hello_world( 'text', 'html', 'echo' );
    }

    function hello_world( 'text', 'html', 'echo' )
    {
        $start_el = '<{$html}>';
        $end_el = '</{$html}>';
        if ( $echo )
        {
            return print "{$start_el}{$some}{$end_el}";
        }

        return "{$start_el}{$some}{$end_el}";
    }
} // END Class 

}

// API: public functions
function the_hello_world( $args( 'echo' => true ) )
{
    $new = new WPSE_HelloWorld();
    return $new->hello_world( $args );
}

function get_hello_world( array( $args( 'echo' => false) ) )
{
    $new = new WPSE_HelloWorld();
    return $new->hello_world( $args );
}

// then you can call it like get_the_title() or the_title(), which you know from the WP API:
// 'echo' is set to false per default:
$some_var = get_hello_world( array( 'text' => 'hello reader', 'html' => 'strong' ) );
# *returns* "<strong>hello reader</strong>"

// 'echo' is set to true per default:
the_hello_world( array( 'text' => 'hello reader', 'html' => 'strong' ) );
# *prints/echos* "<strong>hello reader</strong>"

注意:也请阅读评论中张贴到Q的链接@ t310s。


只是好奇,为什么您希望您的插件文件被wordpress包含多次?
hakre 2011年

@hakre我到底在哪里说这个?对不起,妈妈很累。
凯撒

1
@kaiser,我想@hakre指的是if( ! class_exists )您开头的行?
jjeaton

1
@hakre我假设@kaiser正在执行class_exists检查,不是因为可以再包含一次,而是避免与另一个类发生冲突?
Michal Mau

是的,我想知道class_exists。
hakre 2011年

4

对于插件作者而言,这纯粹是一种风格选择。在速度方面没有真正的区别。


1

类通常不会在性能方面带来任何好处,但是它们也很少有负面影响。它们的真正好处是使代码更清晰并避免名称空间冲突。


但是,正如@hakre所提到的,在全局函数上使用前缀时,名称空间冲突实际上没有什么不同。在这种情况下,“更干净”的代码和防止名称空间冲突是同义词,不是吗?
AlxVallejo 2012年

@AlxVallejo我猜是这样的:)
Bainternet

0

在大多数情况下,如果您使用函数,则会在每个函数名称中放置插件的名称,因此,有效的是,如果插件具有许多功能,则该名称将重复复制十二次。 。

使用类时,您只需在类名中输入一次插件名称即可。

此外,您可以使用继承或其他oo构造以非常干净的方式实现行为。前一个例子:

class animalplugin{
  //plugin functions...
  function talk(){print "animalnoise";}
}
class animalplugin_with_cat_mods extends abcplugin{
  //cat functions overrides
  function talk(){print "meow";}
}
if (iscat()){
  new animalplugin_with_cat_mods();
} else {
  new animalplugin();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.