Php 如何初始化静态变量

Php 如何初始化静态变量,php,class,static-members,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

我有以下代码:

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
);
这给了我以下错误:

分析错误:语法错误,第19行的/home/user/Sites/site/registration/inc/registration.class.inc中出现意外的“(”,应为“)”

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


有人有一些指针吗?

在这部分代码中不能进行函数调用。如果您创建的init()类型方法在任何其他代码执行之前执行,那么您将能够填充该变量。

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

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

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

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

class Foo {
  static $bar;
}
Foo::$bar = array(…);


现在可以处理一些表达式

/* 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();
}

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

例如:

class MyClass { public static function static_init() { } }
在类加载器中,执行以下操作:

include($path . $klass . PHP_EXT);
if(method_exists($klass, 'static_init')) { $klass::staticInit() }
$rc = new ReflectionClass($klass);
if(in_array('StaticInit', $rc->getInterfaceNames())) { $klass::staticInit() }
更重要的解决方案是使用ReflectionClass接口:

interface StaticInit { public static function staticInit() { } }
class MyClass implements StaticInit { public static function staticInit() { } }
在类加载器中,执行以下操作:

include($path . $klass . PHP_EXT);
if(method_exists($klass, 'static_init')) { $klass::staticInit() }
$rc = new ReflectionClass($klass);
if(in_array('StaticInit', $rc->getInterfaceNames())) { $klass::staticInit() }

我宁愿简单地创建一个getter函数,而不是找到一种让静态变量工作的方法。如果您需要属于特定类的数组,并且实现起来要简单得多,那么它也很有用

class MyClass
{
   public static function getTypeList()
   {
       return array(
           "type_a"=>"Type A",
           "type_b"=>"Type B",
           //... etc.
       );
   }
}
只要在需要列表的地方调用getter方法即可。例如:

if (array_key_exists($type, MyClass::getTypeList()) {
     // do something important...
}

下面是一个代码示例,希望对您有所帮助。注意初始化器函数如何只调用一次

此外,如果您反转对
StaticClass::initializeStStateArr()
$st=new StaticClass()
的调用,您将得到相同的结果

$ cat static.php
<?php

class StaticClass {

  public static  $stStateArr = NULL;

  public function __construct() {
    if (!isset(self::$stStateArr)) {
      self::initializeStStateArr();
    }
  }

  public static function initializeStStateArr() {
    if (!isset(self::$stStateArr)) {
      self::$stStateArr = array('CA' => 'California', 'CO' => 'Colorado',);
      echo "In " . __FUNCTION__. "\n";
    }
  }

}

print "Starting...\n";
StaticClass::initializeStStateArr();
$st = new StaticClass();

print_r (StaticClass::$stStateArr);

最好的方法是创建如下访问器:

/**
* @var object $db : map to database connection.
*/
public static $db= null; 

/**
* db Function for initializing variable.   
* @return object
*/
public static function db(){
 if( !isset(static::$db) ){
  static::$db= new \Helpers\MySQL( array(
    "hostname"=> "localhost",
    "username"=> "root",
    "password"=> "password",
    "database"=> "db_name"
    )
  );
 }
 return static::$db;
}
MyClass::$kIdsByActions[$this->mAction];

然后可以执行static::db();或self::db();从任何地方来。

我结合使用了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() ]]
    }
}

但是一个更好的解决方案是取消静态方法,使用单例模式。然后在构造函数中进行复杂的初始化。或者将其设置为“服务”,并使用DI将其注入任何需要它的类中。

在PHP7.0.1中,我能够定义:

public static $kIdsByActions = array(
  MyClass1::kAction => 0,
  MyClass2::kAction => 1
);
然后像这样使用它:

/**
* @var object $db : map to database connection.
*/
public static $db= null; 

/**
* db Function for initializing variable.   
* @return object
*/
public static function db(){
 if( !isset(static::$db) ){
  static::$db= new \Helpers\MySQL( array(
    "hostname"=> "localhost",
    "username"=> "root",
    "password"=> "password",
    "database"=> "db_name"
    )
  );
 }
 return static::$db;
}
MyClass::$kIdsByActions[$this->mAction];


init()类型方法?你能举个例子吗?这有点像C#中的静态构造函数吗?@Svish:没有。它应该作为常规静态方法在类定义下面调用。第一个答案被否决了。看@Pacerier,我不这么认为。与@Pacerier相比,它的开销很大。问10个人,他们中没有一个人会喜欢它。但是构造函数对一个从未实例化过的抽象类有帮助吗?一个抽象类只有在完成并实例化之后才能有效地使用。上面的设置不必在构造函数中专门完成,只要在使用变量之前调用它就行了。假设在需要静态变量之前调用构造函数不是一个好主意。在创建实例之前,通常需要一个静态值。我喜欢PHP,但有时真的很奇怪。我知道这很旧,但我也使用这种方法。但是,我发现有时不调用Foo::init()。我一直无法找到原因,只是想让大家都知道。@porneL,第一种方法不起作用,因为您无法访问私有变量。第二种方法有效,但它迫使我们将
init
公开,这很难看。什么是更好的解决方案?@Pacerier第一种方法使用公共属性是有原因的。恐怕目前还没有更好的PHP解决方案(Tjeerd Visser的答案还不错)。在类加载器中隐藏hack并不会使它消失,强制执行错误继承,而且它的一点巧妙之处可能会意外中断(例如,当文件显式为require()d时)。@porenel Simple array在PHP5.6.x中对我有效,尽管RFC中没有提到。示例:
classfoo{publicstatic$bar=array(3*4,“b”=>7+8);}var\u dump(Foo::$bar)虽然这是一个优雅的解决方案,但出于性能原因,我不认为它是理想的解决方案,主要是因为数组可能被初始化的次数太多,即大量的堆分配。由于php是用C编写的,我想翻译会解析为一个函数,每次调用返回一个指向数组的指针。。。就我的两分钱。而且函数调用在PHP中很昂贵,所以如果它们不是必需的,最好避免它们。“最好在不必要的时候避免”——不是真的。如果它们(可能)成为瓶颈,就要避免它们。否则这是过早的优化。@blissfreak-如果我们在类中创建一个静态属性,并签入getTypeList(),如果它已经初始化并返回该属性,则可以避免重新实现。如果还没有初始化,初始化它并返回那个值。我真的不想避免函数调用。函数是结构化编程的基础。这与c#中的静态构造函数非常相似,我多年来一直在使用类似的东西,效果非常好。@EmanuelLandeholm,方法一快还是方法二快?@Kris这不是巧合。在回答时,我受到了c#的启发。@Pacier我没有证据,但我怀疑ReflectionClass()可能会带来更多开销。OTOH,第一个方法做出了有点危险的假设,即类装入器装入的任何类中称为“static_init”的任何方法都是静态初始值设定项。这可能会导致一些难以追踪的错误,例如第三方类。但请注意,您创建了类(对象)的实例,因为构造函数是一个公共非静态函数。问题是:PHP是否只支持静态构造函数(不支持创建实例。例如在Java
static{/*中,一些代码访问静态成员*/}
FWIW:What you show d d d