Statik değişkenler nasıl başlatılır


207

Bu kod var:

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
);

Bu da bana şu hatayı veriyor:

Ayrıştırma hatası: sözdizimi hatası, 19. satırdaki /home/user/Sites/site/registration/inc/registration.class.inc dosyasında beklenmeyen '(', '' bekleniyor ')

Yani, sanırım yanlış bir şey yapıyorum ... ama böyle değilse nasıl yapabilirim? Ben mktime şeyler düzenli dizeleri ile değiştirmek, çalışır. Ben bunu yapabilirim, biliyorum Yani bir çeşit böyle ..

Kimsenin işaretçileri var mı?



2
İlk cevap sona erdi. Bkz. Stackoverflow.com/a/4470002/632951
Pacerier

1
@Pacerier Ben öyle düşünmüyorum. Cevap # 2 , Yanıt # 1
Kontrollfreak'e göre

2
@Pacerier 10 kişiye soruyor, hiçbiri bunu tercih etmiyor.
Buffalo,

Yanıtlar:


345

PHP, başlatıcılarda önemsiz olmayan ifadeleri ayrıştıramaz.

Sınıf tanımından hemen sonra kod ekleyerek bu soruna geçici bir çözüm tercih ederim:

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

veya

class Foo {
  private static $bar;
  static function init()
  {
    self::$bar = array(…);
  }
}
Foo::init();

PHP 5.6 şimdi bazı ifadeleri işleyebilir.

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

135
PHP'yi seviyorum, ama bazen çok garip.
Marco Demaio

6
Bunun eski olduğunu biliyorum, ama ben de bu yöntemi kullanıyorum. Ancak, bazen Foo :: init () işlevinin çağrılmadığını fark ettim. Nedenini hiç takip edemedim, ama sadece farkında olmak istedim.
lucifurious

1
@porneL, özel değişkenlere erişiminiz olmadığı için ilk yöntem çalışmaz. İkinci yöntem işe yarıyor ama bizi initçirkin olan kamuya açmaya zorluyor . Daha iyi bir çözüm nedir?
Pacerier

2
@Pacerier ilk yöntem bir nedenle kamu mülkiyetini kullanır. AFAIK şu anda PHP'de daha iyi bir çözüm yok (Tjeerd Visser'in cevabı kötü değil). Sınıf yükleyicideki hack'i gizlemek onu ortadan kaldırmaz, yanlış mirasa zorlar ve beklenmedik bir şekilde kırılabilecek zekice bir şeydir (örneğin, dosya açıkça () d açık olduğunda).
Kornel

1
@porneL Basit dizi benim için PHP 5.6.x içinde çalışır, ancak RFC belirtilmemiş. Örnek:class Foo {public static $bar = array(3 * 4, "b" => 7 + 8);} var_dump(Foo::$bar);
Pang

32

Sınıf yüklemesi üzerinde kontrolünüz varsa, oradan statik başlatma yapabilirsiniz.

Misal:

class MyClass { public static function static_init() { } }

sınıf yükleyicinizde aşağıdakileri yapın:

include($path . $klass . PHP_EXT);
if(method_exists($klass, 'static_init')) { $klass::staticInit() }

Daha ağır bir çözüm, ReflectionClass ile bir arayüz kullanmak olacaktır:

interface StaticInit { public static function staticInit() { } }
class MyClass implements StaticInit { public static function staticInit() { } }

sınıf yükleyicinizde aşağıdakileri yapın:

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

Bu biraz c # statik yapıcı benzer daha, ben yaş için oldukça benzer bir şey kullanıyorum ve harika çalışıyor.
Kris

@EmanuelLandeholm, birinci yöntem daha hızlı veya ikinci yöntem daha hızlı mı?
Pacerier

@Kris Bu bir tesadüf değil. Yanıtlarken c # 'dan ilham aldım.
Emanuel Landeholm

1
@Pacerier Kanıtım yok ama ReflectionClass () 'ın daha fazla yük oluşturabileceğinden şüpheleniyorum. Birinci yöntem olan OTOH, sınıf yükleyicisi tarafından yüklenen herhangi bir sınıfta "static_init" adı verilen herhangi bir yöntemin statik bir başlatıcı olduğu konusunda biraz tehlikeli bir varsayım yapar . Bu, hataların izlenmesinin zor olmasına yol açabilir, örn. üçüncü taraf sınıfları ile.
Emanuel Landeholm

23

Statik değişkenleri çalıştırmanın bir yolunu bulmak yerine, sadece bir alıcı işlevi oluşturmayı tercih ederim. Ayrıca belirli bir sınıfa ait dizilere ihtiyacınız varsa ve uygulanması çok daha basitse yararlıdır.

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

Listeye ihtiyacınız olduğunda, getter yöntemini çağırmanız yeterlidir. Örneğin:

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

11
Bu zarif bir çözüm olsa da, öncelikle dizinin potansiyel olarak başlatılabileceği miktardan dolayı, yani çok sayıda yığın tahsisi nedeniyle performans açısından ideal olduğunu söyleyemem. Php C yazılmış olduğundan, çeviri arama başına bir Array bir işaretçi döndüren bir işleve çözeceğini hayal ediyorum ... Sadece benim iki sent.
zeboidlund

Ayrıca PHP'de işlev çağrıları pahalıdır, bu yüzden gerekli olmadıklarında bunlardan kaçınmak en iyisidir.
Mark Rose

14
"gerekli olmadığında onları önlemek için en iyisi" - gerçekten değil. Darboğaz haline gelebilirlerse onlardan kaçının. Aksi takdirde erken optimizasyon.
psycho brm

2
@blissfreak - sınıfta statik bir özellik yaratırsak ve zaten başlatılmışsa getTypeList () 'i kontrol edip geri döndürürseniz, yeniden reaksiyondan kaçınılabilir. Henüz başlatılmadıysa, başlatın ve bu değeri döndürün.
6:13

12
İşlev çağrılarından kaçınmaya çalışmıyorum. Fonksiyonlar yapılandırılmış programlamanın temelidir.
6:13

11

Tjeerd Visser'in ve porneL'in cevabının bir kombinasyonunu kullanıyorum.

class Something
{
    private static $foo;

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

    public static bar()
    {
        [[ do something with self::getFoo() ]]
    }
}

Ancak daha da iyi bir çözüm, statik yöntemleri ortadan kaldırmak ve Singleton desenini kullanmaktır. Sonra sadece yapıcıda karmaşık başlatmayı yaparsınız. Ya da bir "hizmet" yapın ve DI'yi ihtiyacı olan herhangi bir sınıfa yerleştirmek için kullanın.


10

Tanımda belirtilemeyecek kadar karmaşık. Tanımı null olarak ayarlayabilirsiniz ve sonra yapıcıda, denetleyin ve değiştirilmediyse ayarlayın - ayarlayın:

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

10
ama kurucu hiçbir zaman somutlaştırılmamış soyut bir sınıfta yardımcı olacak mı?
Svish

Soyut bir sınıf, tamamlanıp somutlaştırılmadıkça yararlı bir şekilde kullanılamaz. Yukarıdaki kurulum, değişken kullanılmadan önce bir yerde çağrıldığı sürece özel olarak bir kurucuda yapılmak zorunda değildir.
Alister Bulman

Statik değişken gerekmeden önce kurucunun çağrıldığını varsaymak iyi bir fikir değildir. Çoğunlukla bir örnek oluşturmadan önce statik bir değere ihtiyaç duyar .
ToolmakerSteve

4

Kodun bu bölümünde işlev çağrısı yapamazsınız. Diğer kodlardan önce yürütülecek bir init () türü yöntemi yaparsanız, değişkeni daha sonra doldurabilirsiniz.


init () türü yöntemi? bir örnek verebilir misiniz? Bu tür bir C # statik bir kurucu gibi mi?
Svish

@Svish: Hayır. Normal statik yöntem olarak sınıf tanımının hemen altında çağrılmalıdır.
Vladislav Rastrusny

4

PHP 7.0.1'de bunu tanımlayabildim:

public static $kIdsByActions = array(
  MyClass1::kAction => 0,
  MyClass2::kAction => 1
);

Ve sonra böyle kullanın:

MyClass::$kIdsByActions[$this->mAction];

FWIW: Gösterdiğiniz şey PHP 7 gerektirmiyor; sorusunun sorulduğu sırada iyi çalıştı: "mktime öğelerini normal dizelerle değiştirirsem işe yarar." Bu iş parçacığının aradığı şey, başlatmanın bir veya daha fazla işlevi çağırması gerektiğinde bir statik başlatma yöntemidir .
ToolmakerSteve

3

en iyi yolu böyle bir erişimci oluşturmaktır:

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

o zaman static :: db (); veya self :: db (); herhangi bir yerden.


-1

İşte bir kod örneğinde umut verici bir yardımcı işaretçi. Başlatıcı işlevinin nasıl yalnızca bir kez çağrıldığına dikkat edin.

Ayrıca, aramaları tersine eğer StaticClass::initializeStStateArr()ve $st = new StaticClass()aynı sonucu elde edersiniz.

$ 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);

Hangi verim:

$ php static.php
Starting...
In initializeStStateArr
Array
(
    [CA] => California
    [CO] => Colorado
)

2
Ancak, yapıcı genel bir NONSTATIC işlevi olduğu için bir sınıf (nesne) örneği oluşturduğunuzu unutmayın. Soru: PHP sadece statik yapıcıları destekliyor mu (örnek oluşturma yok. Örneğin Java'daki gibistatic { /* some code accessing static members*/ }
Mitja Gustin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.