2009-03-28 29 views
177

tengo este código:Cómo inicializar variables estáticas

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

Lo que me da el siguiente error:

Parse error: syntax error, unexpected '(', expecting ')' in /home/user/Sites/site/registration/inc/registration.class.inc on line 19

lo tanto, supongo que estoy haciendo algo mal ... pero ¿cómo puedo hacer esto si no es así? Si cambio las cosas de mktime con cadenas normales, funciona. Entonces sé que puedo hacerlo tipo de así ..

¿Alguien tiene algunos indicadores?

+0

http://php.benscom.com/manual/en /language.oop5.static.php#51627 –

+2

La primera respuesta ha sido aprobada. Ver http://stackoverflow.com/a/4470002/632951 – Pacerier

+1

@Pacerier No lo creo. [Answer # 2] (http://stackoverflow.com/a/4470002/2032498) tiene una gran cantidad de gastos generales en comparación con [Answer # 1] (http://stackoverflow.com/a/693799/2032498) – Kontrollfreak

Respuesta

301

PHP no puede analizar expresiones no triviales en inicializadores.

prefiero evitar esto mediante la adición de código justo después de la definición de la clase:

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

o

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

PHP 5.6 puede manejar algunas expresiones ahora.

+117

Me encanta PHP, pero a veces es muy extraño. –

+6

Sé que esto es viejo, pero yo también uso este método. Sin embargo, descubrí que a veces Foo :: init() no se llama. Nunca pude rastrear por qué, pero solo quería que todos lo supieran. – lucifurious

+1

@porneL, el primer método no funcionaría porque no tiene acceso a variables privadas. El segundo método funciona pero nos obliga a hacer público 'init', que es feo. ¿Cuál es una mejor solución? – Pacerier

4

No puede hacer llamadas a funciones en esta parte del código. Si haces un método de tipo init() que se ejecuta antes que cualquier otro código, entonces podrás poblar la variable.

+0

método de tipo init()? podrías dar un ejemplo? ¿Es eso como un constructor estático en C#? – Svish

+0

@Svish: No. Debería llamarse justo debajo de la definición de clase como un método estático regular. –

11

Eso es demasiado complejo para establecer en la definición. Puede ajustar la definición a nulo, sin embargo, y luego en el constructor, comprobarlo, y si no se ha cambiado - configurarlo:

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

pero el constructor será de alguna ayuda en una clase abstracta que nunca se instancia? – Svish

+0

Una clase abstracta no se puede usar de forma útil a menos que se haya completado e instanciado. La configuración anterior no tiene que hacerse específicamente en un constructor, siempre que se llame en algún lugar antes de que se vaya a usar la variable. –

+2

@AlisterBulman, quiso decir una clase estática con métodos estáticos – Pacerier

31

Si tiene control sobre la carga de clases, puede hacer la inicialización estática desde allí.

Ejemplo:

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

en su cargador de clases, hacer lo siguiente:

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

Una solución de peso más pesado sería utilizar una interfaz con ReflectionClass:

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

en su cargador de clases, haga lo siguiente:

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

Esto es más que algo similar a los constructores estáticos en C#, he estado usando algo bastante similar por años y funciona muy bien. – Kris

+0

@EmanuelLandeholm, ¿es el método uno más rápido o el método dos más rápido? – Pacerier

+0

@Kris Eso no es una coincidencia. Me inspiré en C# a la hora de responder. –

22

En lugar de encontrar la forma de hacer que las variables estáticas funcionen, prefiero simplemente crear una función getter. También es útil si necesita matrices que pertenecen a una clase específica, y mucho más simples de implementar.

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

Dondequiera que necesite la lista, simplemente llame al método getter. Por ejemplo:

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

Si bien esta es una solución elegante, no diría que es ideal por razones de rendimiento, principalmente debido a la cantidad de veces que la matriz podría inicializarse, es decir, mucha asignación de montón. Dado que php está escrito en C, me imagino que la traducción se resolvería en una función que devuelva un puntero a una matriz por llamada ... Solo mis dos centavos. – zeboidlund

+0

Además, las llamadas a funciones son caras en PHP, por lo que es mejor evitarlas si no son necesarias. –

+12

"lo mejor es evitarlos cuando no es necesario" - en realidad no. Evítelos si (podrían) convertirse en cuellos de botella. De lo contrario, es una optimización prematura. –

0

Aquí hay un puntero con suerte útil, en un ejemplo de código. Observe cómo la función de inicialización solo se llama una vez.

Además, si invierte las llamadas a StaticClass::initializeStStateArr() y $st = new StaticClass() obtendrá el mismo resultado.

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

que produce:

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

Pero tenga en cuenta que creó una instancia de clase (objeto) porque el constructor es una función NONSTATICA pública. La pregunta es: ¿soporta PHP constructores estáticos solamente (sin creación de instancias. Por ejemplo, como en Java 'static {/ * algún código que acceda a miembros estáticos * /}' –

2

mejor manera es crear un descriptor de acceso de esta manera:

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

entonces usted puede hacer estática :: db(); o self :: db(); de donde sea.

10

Uso una combinación de la respuesta de Tjeerd Visser y 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() ]] 
    } 
} 

Pero una solución aún mejor es eliminar los métodos estáticos y utilizar el patrón de Singleton. Luego, acaba de hacer la inicialización complicada en el constructor. O conviértalo en un "servicio" y usa DI para inyectarlo en cualquier clase que lo necesite.

2

En PHP 7.0.1, yo era capaz de definir esto:

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

y luego usarlo como esto:

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