2009-03-28 38 views
177

tôi có mã này:Làm thế nào để khởi tạo các biến tĩnh

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

nào mang lại cho tôi những lỗi sau:

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

Vì vậy, tôi đoán tôi đang làm gì đó sai ... nhưng làm thế nào tôi có thể làm điều này nếu không thích điều đó? Nếu tôi thay đổi công cụ mktime bằng các chuỗi thông thường, nó hoạt động. Vì vậy, tôi biết rằng tôi có thể làm điều đó loại như thế ..

Bất kỳ ai cũng có một số gợi ý?

+0

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

+2

Câu trả lời đầu tiên được bỏ phiếu. Xem http://stackoverflow.com/a/4470002/632951 – Pacerier

+1

@Pacerier Tôi không nghĩ vậy. [Trả lời # 2] (http://stackoverflow.com/a/4470002/2032498) có rất nhiều chi phí so với [Answer # 1] (http://stackoverflow.com/a/693799/2032498) – Kontrollfreak

Trả lời

301

PHP không thể phân tích cú pháp biểu thức không tầm thường trong khởi tạo.

Tôi thích làm việc này bằng cách thêm mã ngay sau khi định nghĩa của lớp:

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

hoặc

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

PHP 5.6 có thể xử lý một số biểu hiện bây giờ.

+117

Tôi yêu PHP, nhưng đôi khi nó thực sự kỳ quặc. –

+6

Tôi biết điều này là cũ, nhưng tôi cũng sử dụng phương pháp này. Tuy nhiên, tôi thấy rằng đôi khi Foo :: init() không được gọi. Tôi đã không bao giờ có thể theo dõi lý do tại sao, nhưng chỉ muốn làm cho tất cả nhận thức được. – lucifurious

+1

@porneL, phương pháp đầu tiên sẽ không hoạt động vì bạn không có quyền truy cập vào các biến riêng tư. Phương thức thứ hai hoạt động nhưng nó buộc chúng ta làm cho công thức 'init' trở nên xấu xí. Giải pháp tốt hơn là gì? – Pacerier

4

Bạn không thể thực hiện các cuộc gọi chức năng trong phần này của mã. Nếu bạn thực hiện một phương thức init() được thực hiện trước khi bất kỳ mã nào khác thực hiện thì bạn sẽ có thể điền biến đó sau đó.

+0

phương thức init()? bạn có thể đưa ra một ví dụ? là loại như một nhà xây dựng tĩnh trong C#? – Svish

+0

@Svish: Không. Nó nên được gọi dưới định nghĩa lớp dưới dạng một phương thức tĩnh thông thường. –

11

Quá phức tạp để đặt trong định nghĩa. Bạn có thể đặt định nghĩa thành null mặc dù và sau đó trong hàm tạo, hãy kiểm tra và nếu nó chưa được thay đổi - hãy đặt nó:

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

nhưng liệu hàm tạo có được trợ giúp trong lớp trừu tượng không bao giờ được khởi tạo không? – Svish

+0

Một lớp trừu tượng không thể được sử dụng hữu ích trừ khi nó được hoàn thành và khởi tạo. Việc thiết lập ở trên không phải được thực hiện cụ thể trong một hàm tạo, miễn là nó được gọi ở đâu đó trước khi biến sẽ được sử dụng. –

+2

@AlisterBulman, anh ấy có nghĩa là một lớp tĩnh với các phương thức tĩnh – Pacerier

31

Nếu bạn có quyền kiểm soát tải lớp, bạn có thể thực hiện khởi tạo tĩnh từ đó.

Ví dụ:

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

trong bộ nạp lớp của bạn, hãy thực hiện như sau:

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

Một giải pháp trọng lượng nặng hơn sẽ sử dụng một giao diện với ReflectionClass:

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

trong trình tải lớp của bạn, hãy làm như sau:

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

Điều này là nhiều hơn một chút tương tự như các nhà xây dựng tĩnh trong C#, tôi đã sử dụng một cái gì đó khá giống với lứa tuổi và nó hoạt động tuyệt vời. – Kris

+0

@EmanuelLandeholm, vậy phương pháp nhanh hơn hoặc phương pháp hai nhanh hơn? – Pacerier

+0

@Kris Đó không phải là trùng hợp ngẫu nhiên. Tôi đã được truyền cảm hứng bởi C# tại thời điểm trả lời. –

22

Thay vì tìm cách để biến các biến tĩnh hoạt động, tôi chỉ muốn tạo một hàm getter. Cũng hữu ích nếu bạn cần mảng thuộc về một lớp cụ thể, và đơn giản hơn rất nhiều để thực hiện.

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

Bất cứ nơi nào bạn cần danh sách, chỉ cần gọi phương thức getter. Ví dụ:

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

Trong khi đây là một giải pháp thanh lịch, tôi sẽ không nói nó lý tưởng vì lý do hiệu suất, chủ yếu là do số lần mảng có khả năng được khởi tạo - tức là, rất nhiều phân bổ đống. Vì php được viết bằng C, tôi hình dung bản dịch sẽ giải quyết thành một hàm trả về một con trỏ tới một Mảng cho mỗi cuộc gọi ... Chỉ hai xu của tôi. – zeboidlund

+0

Hơn nữa, các cuộc gọi hàm rất tốn kém trong PHP, vì vậy tốt nhất nên tránh chúng nếu chúng không cần thiết. –

+12

"tốt nhất để tránh chúng khi không cần thiết" - không thực sự. Tránh chúng nếu chúng (có thể) trở thành tắc nghẽn. Nếu không thì đó là tối ưu hóa sớm. –

0

Đây là con trỏ hữu ích hy vọng, trong ví dụ về mã. Lưu ý cách hàm khởi tạo chỉ được gọi một lần.

Ngoài ra, nếu bạn đảo ngược các cuộc gọi đến StaticClass::initializeStStateArr()$st = new StaticClass() bạn sẽ nhận được kết quả tương tự.

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

nào mang lại:

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

Nhưng xin lưu ý rằng bạn đã tạo một thể hiện của lớp (đối tượng), bởi vì hàm tạo là một hàm NONSTATIC công khai. Câu hỏi là: hiện PHP chỉ hỗ trợ các hàm tạo tĩnh (không tạo ra cá thể) Ví dụ như trong Java 'static {/ * một số mã truy cập các thành viên tĩnh * /}' –

2

cách tốt nhất là tạo ra một accessor như thế này:

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

sau đó bạn có thể làm tĩnh :: db(); hoặc tự :: db(); từ bất cứ nơi nào.

10

Tôi sử dụng kết hợp câu trả lời của Tjeerd Visser và 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() ]] 
    } 
} 

Nhưng một giải pháp tốt hơn nữa là loại bỏ các phương pháp tĩnh và sử dụng mẫu Singleton. Sau đó, bạn chỉ cần khởi tạo phức tạp trong hàm tạo. Hoặc làm cho nó thành một "dịch vụ" và sử dụng DI để tiêm nó vào bất kỳ lớp nào cần nó.

2

Trong PHP 7.0.1, tôi đã có thể xác định này:

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

Và sau đó sử dụng nó như thế này:

MyClass::$kIdsByActions[$this->mAction]; 
Các vấn đề liên quan