【问题标题】:When is necessary to use static methods?什么时候需要使用静态方法?
【发布时间】:2013-08-16 06:20:50
【问题描述】:

我认为通常我们使用静态方法是因为我们不需要实例化对象。并且我们可以使用className::staticFunction来调用静态方法,bub今天发现:

test1.php

<?php
class Foo { 
    static public function helloWorld() {
        print "Hello world " ;
    }
}
Foo::helloWorld();

test2.php

<?php
class Foo { 
    public function helloWorld() {
        print "Hello world " ;
    }
}
Foo::helloWorld();

问题:

以上两个脚本都有效。我们没有将函数声明为static,我们仍然可以使用className::staticFunction 来调用函数。为什么我们需要使用静态方法?

【问题讨论】:

标签: php


【解决方案1】:

我们没有将函数声明为静态,我们仍然可以使用className::staticFunction

你可能没有注意到的是 PHP 抱怨第二种调用:

PHP 严格标准:非静态方法 Foo::helloWorld() 不应在第 1 行的 php shell 代码中静态调用

严格标准:非静态方法Foo::helloWorld()不应在第1行的php shell代码中静态调用

要使这些通知可见,您需要使用ini_set() 或通过php.ini 配置文件将error_reporting 的值设置为-1;顺便说一句,在开发过程中建议这样做。

结论

静态调用的函数应声明为static function xyz()

更新

顺便说一句,使用范围解析运算符:: 并不一定意味着您正在进行静态调用;考虑这个例子:

class Foo 
{ 
    public function helloWorld() 
    {
        print "Hello world ";
    }

    public function doSomething()
    {
        self::helloWorld();
    }
}

$f = new Foo;
$f->doSomething();

这是因为使用self:: 而不是Foo:: 不会改变调用“模式”(除非您调用的方法被定义为static)。

【讨论】:

    【解决方案2】:

    静态方法的“问题”在于它们的调用方式:

    Foo::bar();
    

    对静态方法的任何调用都必然是硬编码的,不能轻易被替换。比较:

    $foo->bar();
    

    $foo 在这里是一个变量,这意味着可以替换bar() 的确切对象和实现。这对于依赖注入很重要,也是依赖注入的基础。

    您将使用静态方法:

    • 首先是不需要单个对象实例的情况
    • 在实例化对象之前需要做的任何事情
    • 替代对象构造函数,例如DateTime::createFromFormat() 而不是new DateTime
    • 您 100% 确定永远不需要替换或模拟的幂等实用程序函数

    可能在其他场景中到处使用静态函数,但这些是要点。您需要注意,将方法声明为静态意味着您需要静态调用它,这意味着它的调用时使用不能真正改变。有关此主题的长条约,请阅读How Not To Kill Your Testability Using Statics

    【讨论】:

      【解决方案3】:

      好吧,一个简单的 hello world 程序可能无法显示出很大的区别,那就是 static 与 not 的用法,但看看这个类

      class foo {
      
      
          private $a = 1;
      
          private static $b = 2;
      
      
          public function foobar()
          {
              echo $this->a;
          }
      
      }
      

      在上面的这个类中,如果你静态调用foobar,那么$this-&gt;a 将无法解析。

      【讨论】:

        【解决方案4】:

        PHP 就是这样有趣,但我通常会有一个实用程序类,它接受事物的参数来执行逻辑并返回。像这样的东西不需要实例化的类。正确调用方法取决于用户/开发人员(阅读:使用正确的方法访问器)。

        【讨论】:

          【解决方案5】:

          当您处理基于 OOP 的大型项目时,毫无疑问,您会使用许多类(父类和子类)。这样做的一个不幸结果是,为了访问来自不同类的元素,必须手动将它们传递给每个类(或者更糟的是,将实例存储在全局变量中)。这可能会非常令人沮丧,并可能导致代码混乱和整体糟糕的项目设计。值得庆幸的是,静态元素可以从任何上下文(即脚本中的任何位置)访问,因此您可以访问这些方法,而无需在对象之间传递类的实例。

          由于您不需要声明对象实例来访问静态元素,因此可以避免不必要的声明来访问看似简单的函数。

          静态元素在类的每个实例中都可用,因此您可以设置希望对类型的所有成员可用的值。

          【讨论】:

          • 你是在提倡全局状态,并且在这里贬低依赖注入“太复杂”???
          • 如果您必须通过其他对象传递对象才能使事情正常工作,那么您做错了。通常的做法是在创建对象的时候把最基本的对象放到其他需要的对象里面(然后再把这些放到其他对象里面),调用的时候把所有的对象都放在自己所属的地方,不用传递。
          【解决方案6】:

          从上面的例子test1.php

          helloworld() 函数不能覆盖重载,因为您添加了静态关键字。

          但是在第二个示例中,test2.php

          helloworld() 函数可以重载覆盖

          插图:1(作品)

          <?php
          class Foo {
              function helloWorld() {
                  print "Hello world " ;
              }
          }
          
          class Foo1 extends Foo
          {
              function helloWorld()
              {
                  echo "Foo's World";
              }
          }
          $Foo1 = new Foo1();
          $Foo1->helloWorld(); //Foo's World
          

          插图:2(失败)

          不能使静态方法 Foo::helloWorld() 非静态

          <?php
          class Foo {
              static function helloWorld() {
                  print "Hello world " ;
              }
          }
          
          class Foo1 extends Foo
          {
              function helloWorld()
              {
                  echo "Foo's World";
              }
          }
          $Foo1 = new Foo1();
          $Foo1->helloWorld();
          

          【讨论】:

          • 您可以很好地扩展和覆盖静态方法/类。你的意思是,如果你静态调用它,它就不能再动态调用了。
          • 在您的扩展示例中,您尝试使 static 方法非静态。当然那是行不通的。如果您也将Foo1::helloWorld 设为静态,则可以很好地覆盖它。但是,您仍然不能/不应该将其称为对象方法。
          猜你喜欢
          • 2010-09-10
          • 2016-02-15
          • 2011-03-23
          • 2021-06-07
          • 1970-01-01
          • 2014-10-15
          • 2012-09-16
          • 2010-09-17
          • 1970-01-01
          相关资源
          最近更新 更多