2009-02-10 37 views
27

Trong PHP, nếu một thuộc tính tĩnh được định nghĩa trong lớp cha, nó không thể được ghi đè trong lớp con. Nhưng tôi tự hỏi nếu có bất kỳ cách nào xung quanh điều này.Thừa kế các thành viên tĩnh trong PHP

Tôi đang cố gắng viết một trình bao bọc cho chức năng của người khác (hơi clunky). Hàm được đề cập có thể được áp dụng cho nhiều loại dữ liệu khác nhau nhưng yêu cầu các cờ và tùy chọn khác nhau cho mỗi loại. Nhưng 99% thời gian, mặc định cho mỗi loại sẽ đủ.

Sẽ tốt hơn nếu điều này có thể được thực hiện với kế thừa, mà không cần phải viết các hàm mới mỗi lần. Ví dụ:

class Foo { 
    public static $default = 'DEFAULT'; 

    public static function doSomething ($param = FALSE) { 
     $param = ($param === FALSE) ? self::$default : $param; 
     return $param; 
    } 
} 

class Bar extends Foo { 
    public static $default = 'NEW DEFAULT FOR CHILD CLASS'; 
} 

echo Foo::doSomething() . "\n"; 
// echoes 'DEFAULT' 

echo Bar::doSomething() . "\n"; 
// echoes 'DEFAULT' not 'NEW DEFAULT FOR CHILD CLASS' 
// because it references $default in the parent class :(

Trả lời

15

Ví dụ điển hình về lý do sử dụng thống kê dưới dạng hình cầu (trong trường hợp này) là một ý tưởng tồi bất kể ngôn ngữ.

Phương pháp mạnh mẽ nhất là tạo nhiều lớp con triển khai của lớp cơ sở "Hành động" trừu tượng.

Sau đó, để thử và loại bỏ một số phiền toái của việc khởi tạo một thể hiện của lớp chỉ để gọi đó là các phương thức, bạn có thể bọc nó trong một nhà máy nào đó.

Ví dụ:

abstract class AbstractAction { 
    public abstract function do(); 
} 

class FooAction extends AbstractAction { 
    public function do() { 
    echo "Do Foo Action"; 
    } 
} 

class BarAction extends AbstractAction { 
    public function do() { 
    echo "Do Bar Action"; 
    } 
} 

Sau đó tạo một nhà máy để "viện trợ" trong instantiation của hàm

class ActionFactory { 
    public static function get($action_name) { 
    //... return AbstractAction instance here 
    } 
} 

Sau đó, sử dụng nó như:

ActionFactory::get('foo')->do(); 
27

Bản phát hành PHP 5.3.0 sắp tới bao gồm late static binding, có thể hữu ích. Sử dụng tính năng này, bạn có thể sử dụng một biến tĩnh bên trong một phương thức tĩnh và để cho liên kết tĩnh trễ chăm sóc việc tìm ra phương thức "đúng".

class Foo { 
    public static function getDefault() { 
     static $default = 'DEFAULT'; 
     return $default; 
    } 
    public static function doSomething ($param) { 
     $default=static::getDefault(); // here is the late static binding 
     $param = ($param === FALSE) ? $default : $param; 
     return $param; 

    } 
} 

class Bar extends Foo { 
    public static function getDefault() { 
     static $default = 'NEW DEFAULT FOR CHILD CLASS'; 
     return $default; 
    } 
} 
+1

Điều này sẽ rất đáng yêu và cảm ơn thông tin. Nhưng than ôi, tôi cần một cái gì đó sẽ chạy trong môi trường sản xuất hiện tại của tôi (5.2.6). CẢM ƠN! – PartialOrder

24

Thật sự tôi nghĩ rằng nó không đúng: bạn có thể ovverride propeties tĩnh (bạn cần> = 5.3 PHP cho điều đó). Nhưng bạn phải cẩn thận khi refrencing cho rằng thuộc tính tĩnh (và điều này là sai lầm trong mã gốc)

Bạn cần phải sử dụng tĩnh :: $ myStaticProperty thay vì sử dụng tự :: $ myStaticProperty

self :: sẽ chỉnh lại thành lớp hiện tại vì vậy nếu bạn ở bên trong một phương thức tĩnh kế thừa, điều này sẽ điều chỉnh thuộc tính tĩnh của lớp đó đã định nghĩa phương thức đó! Trong khi sử dụng từ khóa tham chiếu tĩnh :: sẽ hoạt động như $ this - khi bạn đang sử dụng các phương thức/propeties mẫu.

doSomething() là một phương thức tĩnh kế thừa trong lớp Bar trong ví dụ của bạn. Vì bạn đã sử dụng self :: ở đây, nó sẽ tham chiếu đến thuộc tính tĩnh của lớp Foo. Đây là lý do tại sao bạn không thấy bất kỳ sự khác biệt nào ... Cố gắng thay đổi tự :: thành tĩnh ::!

Đây là ví dụ về mã - Tôi đã tự mình sử dụng để kiểm tra những thứ đó. Chúng ta có thuộc tính tĩnh/phương thức thừa kế, ghi đè và thay đổi giá trị trong nó - chạy nó và bạn sẽ thấy kết quả!

class A { 

    // a static property - we will test override with it 
    protected static $var = 'class A var - override'; 
    // a static property - we will test value overwrite with it 
    protected static $var2 = 'class A var2 - value overwrite'; 


    public static function myStaticOverridePropertyTest() { 
     return static::$var; 
    } 
    public static function myStaticValueOverwritePropertyTest() { 
     return static::$var2; 
    } 

    /** 
    * This method is defined only here - class B will inherit this one! 
    * We use it to test the difference btw self:: and static:: 
    * 
    * @return string 
    */ 
    public static function myStaticMethodTest() { 
     //return self::getValue(); 
     return static::getValue(); 
    } 

    /** 
    * This method will be overwritten in class B 
    * @return string 
    */ 
    protected static function getValue() { 
     return 'value from class A'; 
    } 
} 


class B extends A { 

    // we override this inherited static property 
    protected static $var = 'class B var - override'; 

    /** 
    * This method is overwritten from class A 
    * @return string 
    */ 
    protected static function getValue() { 
     return 'value from class B'; 
    } 

    /** 
    * We modify the value of the inherited $var2 static property 
    */ 
    public static function modStaticProperty() { 
     self::$var2 = 'class B - altered value! - value overwrite'; 
    } 
} 

echo ("-- testing class A:\n"); 
echo (A::myStaticOverridePropertyTest(). "\n"); 
echo (A::myStaticValueOverwritePropertyTest(). "\n"); 
echo (A::myStaticMethodTest(). "\n"); 

echo ("-- now testing class B:\n"); 
echo (B::myStaticOverridePropertyTest(). "\n"); 
echo (B::myStaticValueOverwritePropertyTest(). "\n"); 
echo (" now invoking B::modStaticProperty()  .\n"); 
B::modStaticProperty(); 
echo (B::myStaticValueOverwritePropertyTest(). "\n"); 

echo ("-- now re-testing class A:\n"); 
echo (A::myStaticOverridePropertyTest(). "\n"); 
echo (A::myStaticValueOverwritePropertyTest(). "\n"); 
echo (A::myStaticMethodTest(). "\n"); 

Sản lượng này sẽ:

- kiểm tra lớp A:
hạng A var - ghi đè
hạng A var2 - Giá trị ghi đè
giá trị từ lớp Một
- lớp đang thử nghiệm B:
biến thể lớp B ghi đè
lớp var2 - giá trị ghi đè
hiện gọi B = modStaticProperty() ...
lớp B - giá trị thay đổi! - giá trị ghi đè
- hiện đang kiểm tra lại lớp A:
biến thể loại A Một số ghi đè
loại B - giá trị thay đổi! - Giá trị ghi đè
giá trị từ lớp Một

Và ở đây chúng ta đang có, bạn có thể thấy sự khác biệt giữa giá trị ghi đè các thuộc tính tĩnh overriden và chỉ ... Em hãy nhìn dòng đầu ra tôi được đánh dấu bằng đậm! Khi chúng ta gọi modStaticProperty() của lớp B, nó cũng thay đổi giá trị của biến tĩnh đó trong lớp A. Kể từ khi tài sản tĩnh đó được thừa hưởng và không được overriden! Hãy suy nghĩ về nó ...

+0

Sẽ không hoạt động nếu các trường công khai và thay đổi bên ngoài. http://sandbox.onlinephpfunctions.com/code/5d5e947898ea3e4f14e742dd9c9792988fd18dac –

+0

TL; DR: Bạn cần sử dụng 'static :: $ myStaticProperty' thay vì sử dụng' self :: $ myStaticProperty';) – T30

Các vấn đề liên quan