PHP中的静态类初始化程序

时间:2010-07-22 19:49:27

标签: php class static constructor initializer

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

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

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

8 个答案:

答案 0 :(得分:106)

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

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
  }
}

然后,在使用中

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

// You'd do this
Singleton::getInstance()->someMethod1();

答案 1 :(得分:92)

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

Foo::init();

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

答案 2 :(得分:55)

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

答案 3 :(得分:3)

我将其发布为答案,因为从PHP 7.4开始,这非常重要。

PHP 7.4的opcache.preload机制使得可以预加载类的操作码。如果使用它预加载包含类定义的文件,则该FPM服务器及其工作程序执行的所有后续脚本将“存在”在该文件中定义的类。 >但副作用将不会生效,并且自动加载器将不需要包含它们的文件,因为该类已“存在” 。这完全击败了依赖于执行包含类定义的文件中的顶级代码的所有静态初始化技术。

答案 4 :(得分:2)

有一种方法可以一次调用init()方法并禁止其使用,您可以将函数变成私有初始化器,并在类声明后将其调用,如下所示:

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

答案 5 :(得分:0)

如果你不喜欢public静态初始化程序,那么反射可以是一种解决方法。

<?php

class LanguageUtility
{
    public static function initializeClass($class)
    {
        try
        {
            // Get a static method named 'initialize'. If not found,
            // ReflectionMethod() will throw a ReflectionException.
            $ref = new \ReflectionMethod($class, 'initialize');

            // The 'initialize' method is probably 'private'.
            // Make it accessible before calling 'invoke'.
            // Note that 'setAccessible' is not available
            // before PHP version 5.3.2.
            $ref->setAccessible(true);

            // Execute the 'initialize' method.
            $ref->invoke(null);
        }   
        catch (Exception $e)
        {
        }
    }
}

class MyClass
{
    private static function initialize()
    {
    }
}

LanguageUtility::initializeClass('MyClass');

?>

答案 6 :(得分:0)

注意:这正是OP所说的。(但未显示代码。)我在此处显示详细信息,以便您可以将其与接受的答案进行比较。我的意思是,OP的本能是恕我直言,胜过他接受的答案。


鉴于接受的答案有多高的评价,我想指出对静态方法的一次初始化的“天真的”答案,几乎没有比Singleton的实现更多的代码了-并且有一个基本优势

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

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


    private static $didInit = false;

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

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

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

MyClass::someMethod1();

将其与接受的答案所需的呼叫进行对比:

MyClass::getInstance->someMethod1();

作为一般原则,在编写课程时,最好一次支付一次编码费用,以使呼叫者更简单。


在所有答案(包括此答案)中,我更喜欢Victor Nicollet's answer。简单。无需额外的编码。没有“高级”编码可以理解。 (我建议添加FrancescoMM的注释,以确保“ init”永远不会执行两次。)

所以我本来可以写这个答案。但是,如此多的人赞成公认的答案,以至于我得出结论,有些人根本不知道明显的“天真”方法(我在这里展示)。将此作为起点。

答案 7 :(得分:-4)

注意 - 提出这个的RFC仍处于草案状态。

class Singleton
{
    private static function __static()
    {
        //...
    }
    //...
}

建议用于PHP 7.x(参见https://wiki.php.net/rfc/static_class_constructor