【问题标题】:When should I use static methods?我什么时候应该使用静态方法?
【发布时间】:2016-02-15 19:34:45
【问题描述】:

我有一个包含 10 个方法的类。 我总是需要使用其中一种方法。现在我想知道,哪种方法更好?

class cls{
    public function func1(){}
    public function func2(){}
    .
    .
    public function func10(){}
}

$obj  = new cls;
$data = $obj->func3(); // it is random, it can be anything (func1, or func9 or ...)

class cls{
    public static function func1(){}
    public static function func2(){}
    .
    .
    public static function func10(){}
}

cls::func3(); // it is random, it can be anything (func1, or func9 or ...)

【问题讨论】:

  • 依赖静态方法通常是个坏主意,因为它们使替换(因此专门化或测试)变得困难。
  • 看起来你有 10 个独立的类,它们都继承自同一个接口。但是如果不解释这些功能的作用,就不可能说如何改进。
  • @Adam 这不是代码审查,他在问一个具体的问题。

标签: php oop


【解决方案1】:

这是一个有趣的话题。我会给你一个面向设计的答案。

在我看来,您永远不应该在良好的 OOP 架构中使用静态类/函数。

当你使用静态时,这是调用一个没有类实例的函数。主要原因通常是表示一个不应多次实例化的服务类。

我会给你 3 个解决方案(从最坏到最好)来实现这一目标:

静态

静态类(只有静态函数)会阻止您使用许多 OOP 功能,例如继承、接口实现。如果你真的想到什么是静态函数,它就是一个以类名命名的函数。 PHP 中已经有了命名空间,为什么还要再添加一层呢?

另一个很大的缺点是您无法定义与静态类和使用它的类的明确依赖关系,这对应用程序的可维护性和可扩展性来说是一件坏事。

单例

单例是一种强制类只有一个实例的方法:

<?php

class Singleton {
    // Unique instance.
    private static $instance = null;

    // Private constructor prevent you from instancing the class with "new".
    private function __construct() {  
    }

    // Method to get the unique instance.
    public static function getInstance() {
        // Create the instance if it does not exist.
        if (!isset(self::$instance)) {
            self::$instance = new Singleton();  
        }

        // Return the unique instance.
        return self::$instance;
    }
}

这是一种更好的方法,因为您可以使用继承、接口并且您的方法将在实例化对象上调用。这意味着您可以定义合同并将low coupling 与使用它的类一起使用。然而,有些人认为singleton as an anti pattern 特别是因为如果你想拥有 2 个或更多具有不同输入属性的类实例(例如连接到 2 个不同数据库的经典示例),你不能不使用对所有代码进行大重构单身人士。

服务

服务是标准类的一个实例。这是一种使代码合理化的方法。这种架构称为 SOA(面向服务的架构)。我举个例子:

如果您想添加一种在商店中向消费者销售产品的方法,并且您有 ProductStoreConsumer 类。你应该在哪里实例化这个方法?我可以保证,如果您认为今天在这三个课程中的一个课程中更合乎逻辑,那么明天可能会是其他任何课程。这会导致大量重复,并且很难找到您要查找的代码在哪里。相反,您可以使用像 SaleHandler 这样的服务类,它知道如何操作您的数据类。

最好使用一个框架来帮助您将它们相互注入 (dependency injection) 以便充分发挥它们的潜力。在 PHP 社区中,您有一个很好的例子来实现这一点,例如 Symfony


总结一下:

  • 如果您没有框架,即使我个人更喜欢手动依赖注入的简单文件,单例也是一种选择。

  • 如果你有一个框架,使用它的依赖注入特性来做这种事情。

  • 您不应该使用静态方法(在 OOP 中)。如果您需要在其中一个类中使用静态方法,这意味着您可以创建一个包含此方法的新单例/服务,并将其注入到需要它的类的实例中。

【讨论】:

  • 因此,我们应该使用更复杂、冗长且容易出错的单例,而不是使用原生且易于使用的功能?我不同意。
【解决方案2】:

答案取决于这些方法的作用。如果您使用它们来改变手头对象的状态,则需要使用实例方法调用。如果它们是独立的功能,那么您可以使用静态版本,但我会质疑为什么它们是类的一部分。

【讨论】:

  • 好的,谢谢,但我没听明白:但是我会质疑为什么他们是一个班级的一部分。
  • 方法/函数在 PHP 中根本不需要成为类的一部分。从简化的示例中很难确定,但如果它们都与类及其代表的内容有关,那么在类中包含方法是很好的。如果它们是单独的关注点,那么将它们分开会更好。
  • "为什么它们是类的一部分" -> GetStringMessageClass::stringOne - GetStringMessageClass::stringTwo,没有类,没有定义字符串是什么的名称(方法名称就是这样做的)它将简单的相关事物包装在一起,例如 stringOne 和 Two。当然会更好,比如GetErrorMessage::invalidTypeMessage,它返回例如“这个值的数据类型无效”等
【解决方案3】:

所以,static 方法有一个非常基本的区别。

要使用静态函数,您不需要将类初始化为对象。例如,Math.pow(),这里的.pow()(在 Java 中;但解释仍然成立)是一个静态方法。

一般规则是使辅助方法static

因此,例如,如果您有一个 Math 类,您就不会希望用仅帮助其他更重要的类的类来填充垃圾收集器。

如果您愿意,您可以将其用作动态初始化程序!

假设您有一个类RSAEncryptionHelper,现在您通常可以不带任何参数对其进行初始化,这将生成一个密钥大小为(例如)512 位的对象;但你也有一个重载的对象构造函数,它从其他类中获取所有属性:

$a = new RSAEncryptionHelper::fromPrimeSet(...);

【讨论】:

  • 是的,我知道,我的问题是,我有一个包含 10 个方法的类。关键是:我总是需要其中一种方法。那么,哪种方法更适合我呢?使用static 方法还是正常编写这些方法?
  • 使用静态方法会更好;你会更容易访问这些方法,更少的垃圾收集,一点性能提升。 :)
【解决方案4】:

在 PHP 类中,您可以使用 类/方法/属性:Abstract、Static、Private、Public 等... 最好的方法是知道如何根据需要在一个类中混合它们,我会给你一个基本的例子:

Person 类中,您有 privatepublic 方法,但是您有一个名为“get_nationality”的方法,所以这是一个你在其他地方需要的函数,但你还没有安装 Person 类,所以这个方法你把它作为 STATIC 这样你就可以调用“get_nationality" 方法而无需安装任何Person 类,这会使您的业务模型更加优化,进而将资源集中在 CPU 中。

【讨论】:

    【解决方案5】:

    静态函数也非常有用,但是 当我必须创建与类独立相关的函数时,我通常会制作 traits

    我不知道这种方法是否更好,但大多数时候我发现它很有用。

    只是在这里分享我的方法,以便我可以更多地了解它的优缺点。

    【讨论】:

    • 如您所愿,这里有一个观点。我不认为在 PHP 中使用特征来实现伪多重继承是一件好事。这打破了SRP,这是强大的 OOP 架构的基础。
    【解决方案6】:

    你可以认为是一个工厂。你会给一些材料,它会给你同样的输出。那么你应该使用static函数。

    class ProductDetails
    {
       public static function getRow($id, PDO $pdo): SingleProduct
       {
         // this function will return an Object. 
       }
    }
    

    我没有在这里定义对象。在您需要单一产品的地方,您可以简单地做到这一点ProductDetails::getRow(10, $pdo);

    【讨论】:

      猜你喜欢
      • 2010-09-17
      • 2011-03-23
      • 1970-01-01
      • 1970-01-01
      • 2011-01-06
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      • 2012-03-23
      相关资源
      最近更新 更多