PHP中的静态类初始化程序

use*_*626 84 php static constructor class initializer

我有一个带有一些静态函数的辅助类.该类中的所有函数都需要一个"重"初始化函数才能运行一次(就好像它是一个构造函数).

实现这一目标是否有良好的做法?

我唯一想到的是调用一个init函数,并且如果它已经运行一次(使用静态$initializedvar)则会中断它的流程.问题是我需要在每个类的函数上调用它.

Pet*_*ley 112

听起来你更喜欢单身而不是一堆静态方法

class Singleton
{
  /**
   * 
   * @var Singleton
   */
  private static $instance;

  private function __construct()
  {
    // Your "heavy" initialization stuff here
  }

  public static function getInstance()
  {
    if ( is_null( self::$instance ) )
    {
      self::$instance = new self();
    }
    return self::$instance;
  }

  public function someMethod1()
  {
    // whatever
  }

  public function someMethod2()
  {
    // whatever
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,在使用中

// As opposed to this
Singleton::someMethod1();

// You'd do this
Singleton::getInstance()->someMethod1();
Run Code Online (Sandbox Code Playgroud)

  • @ircmaxell - 你真的只是谈论单身人士模式本身的问题.任何人在SO上发布的代码都不应该被认为是权威的 - 特别是简单的例子只是为了说明.每个人的情景和情况都不同 (17认同)
  • 20整行??!?!?Jeez,这个答案的作者不知道代码行是一种宝贵的资源吗?!?他们不知道在树上生长! (17认同)
  • @ekevoo我不是Singleton Pattern的作者,你知道.不要杀死信使. (16认同)
  • @PeterBailey除了胶水之外没有任何成就的代码行分散注意力并使代码不易维护. (10认同)
  • 我想-1(但我不会)私有构造函数和`getInstance()`...你会非常难以有效地测试...至少让它受到保护,以便你有选择权. .. (3认同)
  • 请注意,这有经典的Singleton竞争条件.您需要在getInstance函数上使用互斥锁,以便在多个线程正在使用此类的上下文中保证安全. (2认同)
  • 考虑`new static()`而不是`new self()`(这样你就可以覆盖类) (2认同)

Vic*_*let 93

// file Foo.php
class Foo
{
  static function init() { /* ... */ }
}

Foo::init();
Run Code Online (Sandbox Code Playgroud)

这样,在包含类文件时就会发生初始化.您可以确保仅在必要时(并且仅使用一次)使用自动加载.

  • 我不明白你的问题.所有上述内容都发生在包含的文件中. (3认同)
  • @Pacerier如果init()在第二次被调用时不执行任何操作,那么它是否公开就没关系了。/ * ... * /}` (2认同)
  • 这与 PHP 7.4 的 `opcache.preload` 不兼容。如果文件在预加载脚本中预加载,则该类将“存在”,但不会受到该文件中顶级代码的影响 - 并且自动加载将不需要该文件,因为该类存在,并且您也不会需要它因为这会导致类被重新定义! (2认同)

irc*_*ell 55

实际上,我__init__()在需要初始化的静态类上使用公共静态方法(或者至少需要执行一些代码).然后,在我的自动加载器中,当它加载一个类时它会检查is_callable($class, '__init__').如果是,则调用该方法.快速,简单,有效......

  • 对于我们这些使用作曲家的人:我发现了这个:https://packagist.org/packages/vladimmi/construct-static (3认同)
  • 这也是我的建议。我过去做过同样的事情,但称之为“__initStatic()”。感觉就像 PHP 需要的东西,了解 Java。 (2认同)

Too*_*eve 7

注意:这正是 OP 所说的。(但没有显示代码。)我在这里显示了详细信息,以便您可以将其与接受的答案进行比较。我的观点是 OP 的本能是,恕我直言,比他接受的答案要好。


鉴于已接受的答案的投票率如此之高,我想指出静态方法一次性初始化的“天真”答案,几乎没有比单例的实现更多的代码 - 并且具有本质优势。

final class MyClass  {
    public static function someMethod1() {
        MyClass::init();
        // whatever
    }

    public static function someMethod2() {
        MyClass::init();
        // whatever
    }


    private static $didInit = false;

    private static function init() {
        if (!self::$didInit) {
            self::$didInit = true;
            // one-time init code.
        }
    }

    // private, so can't create an instance.
    private function __construct() {
        // Nothing to do - there are no instances.
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是您可以使用简单的静态函数语法进行调用:

MyClass::someMethod1();
Run Code Online (Sandbox Code Playgroud)

将其与接受的答案所需的调用进行对比:

MyClass::getInstance->someMethod1();
Run Code Online (Sandbox Code Playgroud)

作为一般原则,最好在对类进行编码时支付一次编码费用,以使调用者更简单。


如果您不使用 PHP 7.4 opcode.cache,请使用Victor Nicollet 的回答。简单的。不需要额外的编码。没有要理解的“高级”编码。(我建议包括 FrancescoMM 的评论,以确保“init”永远不会执行两次。)请参阅Szczepan 关于为什么 Victor 的技术不适用于opcode.cache.

如果ARE使用opcode.cache,那么据我所知我的回答是那样干净,你可以得到。成本只是MyClass::init();在每个公共方法的开头添加一行。注意:如果您想要公共属性,请将它们编码为get/set对方法,以便您有地方添加该init调用。

(私有成员不需要那个init调用,因为它们不能从外部访问——所以在执行到达私有成员时,已经调用了一些公共方法。)


brz*_*hal 6

有一种方法可以调用init()一次该方法并禁止其使用,您可以将函数转换为私有初始化程序并在类声明后调用它,如下所示:

class Example {
    private static function init() {
        // do whatever needed for class initialization
    }
}
(static function () {
    static::init();
})->bindTo(null, Example::class)();
Run Code Online (Sandbox Code Playgroud)

  • 这看起来很有趣 (4认同)
  • 好吧,事实上,我们甚至不需要 `init()` 方法,即我们可以将所有初始化代码直接放入这个匿名函数中,该函数本身可以充当静态构造函数。 (2认同)
  • 注意:请参阅 [Szczepan 的回答](/sf/answers/4310437911/),它解释了如果您使用 PHP 7.4 的 `opcache.preload` 机制,这样的技术将不起作用。 (2认同)