如何初始化静态变量

Svi*_*ish 204 php class static-members

我有这个代码:

private static $dates = array(
  'start' => mktime( 0,  0,  0,  7, 30, 2009),  // Start date
  'end'   => mktime( 0,  0,  0,  8,  2, 2009),  // End date
  'close' => mktime(23, 59, 59,  7, 20, 2009),  // Date when registration closes
  'early' => mktime( 0,  0,  0,  3, 19, 2009),  // Date when early bird discount ends
);
Run Code Online (Sandbox Code Playgroud)

这给了我以下错误:

解析错误:第19行/home/user/Sites/site/registration/inc/registration.class.inc中的语法错误,意外'(',期待')'

所以,我想我做错了什么......但是如果不是那样的话怎么办呢?如果我用常规字符串更改mktime内容,它就可以工作.所以,我知道我能做到这一点的那种像..

有人有指点吗?

Kor*_*nel 340

PHP无法解析初始值设定项中的非平凡表达式.

我更喜欢通过在定义类之后添加代码来解决这个问题:

class Foo {
  static $bar;
}
Foo::$bar = array(…);
Run Code Online (Sandbox Code Playgroud)

要么

class Foo {
  private static $bar;
  static function init()
  {
    self::$bar = array(…);
  }
}
Foo::init();
Run Code Online (Sandbox Code Playgroud)

PHP 5.6现在可以处理一些表达式.

/* For Abstract classes */
abstract class Foo{
    private static function bar(){
        static $bar = null;
        if ($bar == null)
            bar = array(...);
        return $bar;
    }
    /* use where necessary */
    self::bar();
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢PHP,但有时候真的很奇怪. (132认同)
  • 我知道这是旧的,但我也使用这种方法.但是,我发现有时候不会调用Foo :: init().我从来没有能够找到原因,但只是想让所有人意识到. (6认同)
  • @Pacerier第一种方法使用公共财产是有原因的。AFAIK目前在PHP中没有更好的解决方案(尽管Tjeerd Visser的回答还不错)。隐藏在类加载器中的hack不会使其消失,会导致错误的继承,并且它的一些聪明之处可能会使其意外中断(例如,当文件需要require()d时)。 (2认同)

Ema*_*olm 32

如果您可以控制类加载,则可以从那里进行静态初始化.

例:

class MyClass { public static function static_init() { } }
Run Code Online (Sandbox Code Playgroud)

在类加载器中,执行以下操作:

include($path . $klass . PHP_EXT);
if(method_exists($klass, 'static_init')) { $klass::staticInit() }
Run Code Online (Sandbox Code Playgroud)

更重的解决方案是使用ReflectionClass的接口:

interface StaticInit { public static function staticInit() { } }
class MyClass implements StaticInit { public static function staticInit() { } }
Run Code Online (Sandbox Code Playgroud)

在类加载器中,执行以下操作:

$rc = new ReflectionClass($klass);
if(in_array('StaticInit', $rc->getInterfaceNames())) { $klass::staticInit() }
Run Code Online (Sandbox Code Playgroud)

  • @Pacerier我没有证据,但我怀疑 ReflectionClass() 可能会产生更多开销。OTOH,第一种方法做出了有点危险的假设,即类加载器加载的*任何*类中名为“static_init”的*任何*方法都是静态初始化程序。这可能会导致一些难以追踪的错误,例如。与第三方课程。 (2认同)

小智 23

我没有找到让静态变量工作的方法,而是简单地创建一个getter函数.如果您需要属于特定类的数组,并且实现起来要简单得多,也会很有帮助.

class MyClass
{
   public static function getTypeList()
   {
       return array(
           "type_a"=>"Type A",
           "type_b"=>"Type B",
           //... etc.
       );
   }
}
Run Code Online (Sandbox Code Playgroud)

无论您需要列表,只需调用getter方法即可.例如:

if (array_key_exists($type, MyClass::getTypeList()) {
     // do something important...
}
Run Code Online (Sandbox Code Playgroud)

  • "在没有必要时最好避免使用它们" - 不是真的.如果他们(可能)成为瓶颈,请避免使用它们.否则就是过早优化. (13认同)
  • 虽然这是一个优雅的解决方案,但我不认为它是出于性能原因的理想选择,主要是因为数组可能被初始化的次数 - 即大量的堆分配.由于php是用C语言编写的,我想这个翻译会解析为每个调用返回一个指向数组的指针的函数......只需要我的两分钱. (11认同)
  • 我真的不想试图避免函数调用.函数是结构化编程的基础. (11认同)
  • @blissfreak-如果我们在类中创建一个静态属性,并检查getTypeList()是否已经初始化并返回它,则可以避免实现。如果尚未初始化,则将其初始化并返回该值。 (2认同)

小智 11

我使用了Tjeerd Visser和porneL的答案.

class Something
{
    private static $foo;

    private static getFoo()
    {
        if ($foo === null)
            $foo = [[ complicated initializer ]]
        return $foo;
    }

    public static bar()
    {
        [[ do something with self::getFoo() ]]
    }
}
Run Code Online (Sandbox Code Playgroud)

但更好的解决方案是取消静态方法并使用Singleton模式.然后你只需要在构造函数中进行复杂的初始化.或者将其作为"服务"并使用DI将其注入任何需要它的类中.


Ali*_*man 10

这太复杂了,无法在定义中设置.您可以将定义设置为null,然后在构造函数中检查它,如果它还没有更改 - 设置它:

private static $dates = null;
public function __construct()
{
    if (is_null(self::$dates)) {  // OR if (!is_array(self::$date))
         self::$dates = array( /* .... */);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 但构造函数是否会在一个从未实例化的抽象类中提供任何帮助? (10认同)
  • @AlisterBulman,他的意思是静态类的静态方法 (3认同)