2015-09-24 19 views
10

Với sự ràng buộc tĩnh muộn trong PHP v5.3, người ta có thể khai báo một cách hữu ích các phương thức static trong giao diện; với các đặc điểm trong PHP v5.4, các phương thức có thể là static hoặc abstract nhưng không phải cả hai. Điều này có vẻ phi logic và không nhất quán.Tại sao các đặc điểm PHP không có các phương thức trừu tượng tĩnh?

Cụ thể, giả sử người ta có giao diện mà một đặc điểm cung cấp tất cả triển khai, ngoại trừ một phương pháp tĩnh; trừ khi phương thức đó được khai báo trong đặc điểm, các phân tích tĩnh balk tại bất kỳ tham chiếu nào từ bên trong đặc điểm đó. Nhưng việc cung cấp một thực thi cụ thể bên trong đặc điểm này không còn buộc thực hiện/sử dụng các lớp học để cung cấp việc thực hiện của riêng chúng — điều đó là nguy hiểm; abstract static sẽ là lý tưởng, nhưng không được phép.

Giải thích cho mâu thuẫn này là gì? Bạn khuyên bạn nên giải quyết vấn đề này như thế nào?

interface MyInterface 
{ 
    public static function getSetting(); 
    public function doSomethingWithSetting(); 
} 

trait MyTrait 
{ 
    public abstract static function getSetting(); // I want this... 

    public function doSomethingWithSetting() { 
     $setting = static::getSetting(); // ...so that I can do this 
     /* ... */ 
    } 
} 

class MyClass implements MyInterface 
{ 
    use MyTrait; 
    public static function getSetting() { return /* ... */ } 
} 
+0

Tôi đã thử những gì bạn muốn trong php 5.6.10 (CLI) và nó làm việc .. Tôi đã làm cho bạn sai hay bạn muốn điều này cho php 5.4? – Mjh

+1

@Mjh: Cài đặt ['error_reporting'] của bạn (https://secure.php.net/manual/en/errorfunc.configuration.php#ini.error-reporting) là gì? Ở trên sẽ làm phát sinh lỗi 'E_STRICT'. – eggyal

+0

Tôi đặt 'error_reporting (E_ALL);'. Tôi đã khai báo một đặc điểm với 'public static static test test();' và tôi có 'PHP Strict Standards: Hàm tĩnh MyTest :: test() không nên trừu tượng trong mã trình bao php trên dòng 1'. Khi tôi tạo một lớp có sử dụng đặc điểm và nếu tôi không triển khai phương thức trừu tượng thì tôi nhận được 'Lỗi nghiêm trọng PHP: Lớp MyTestClass chứa 1 phương thức trừu tượng và do đó phải được khai báo trừu tượng hoặc thực hiện các phương thức còn lại (MyTestClass :: test) trong mã shell php trên dòng 1'. Điều đó có giúp ích gì không? – Mjh

Trả lời

5

TL; DR: Bạn thể xác định abstract static trên trait s, nhưng internals xét thấy thực tế xấu và có thể loại bỏ nó trong tương lai.

Chưa có nhiều caffeine, nhưng tôi sẽ giải quyết nó.

Nghiêm ngặt, abstract nghĩa là phân loại phụ phải triển khai và static chỉ là mã cho lớp cụ thể này. Kết hợp với nhau, abstract static có nghĩa là "sub-class phải thực thi mã cho lớp cụ thể này". Khái niệm hoàn toàn trực giao.

Nhưng ... PHP 5.3+ hỗ trợ kế thừa tĩnh nhờ LSB. Vì vậy, chúng tôi thực sự mở định nghĩa đó lên một chút: self lấy định nghĩa tĩnh trước đây, trong khi static trở thành "mã cho lớp cụ thể này hoặc bất kỳ lớp con nào của nó". Định nghĩa mới của abstract static là "lớp con phải triển khai mã cho lớp cụ thể này hoặc bất kỳ lớp con nào của nó". Điều này có thể dẫn một số người, những người nghĩ về static theo nghĩa nghiêm ngặt, để nhầm lẫn. Xem ví dụ bug #53081.

Điều gì làm cho trait trở nên đặc biệt để gợi ý cảnh báo này? Vâng, hãy nhìn vào các engine code mà thực hiện thông báo:

if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) { 
    zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); 
} 

Đó là mã nói nơi chỉ một abstract static được phép nằm trong một interface. Nó không phải là duy nhất cho các đặc điểm, nó là duy nhất cho định nghĩa của abstract static. Tại sao? Vâng, hãy chú ý có một trường hợp góc nhỏ trong định nghĩa của chúng tôi:

sub-class must implement code for this specific class or any of its sub-classes

Với mã này:

abstract class Foo { 
    abstract public static function get(); 
} 

định nghĩa đó có nghĩa là tôi nên có thể gọi Foo::get. Sau khi tất cả Foo là một lớp (xem từ khóa "lớp" đó) và theo định nghĩa chặt chẽ, get có nghĩa là được triển khai trong lớp đó Foo. Nhưng rõ ràng là không có ý nghĩa, bởi vì, chúng ta quay trở lại với tính trực giao của tĩnh chặt chẽ.

Nếu bạn thử nó trong PHP, bạn sẽ có được câu trả lời lý do duy nhất có thể:

Cannot call abstract method Foo::get()

Vì vậy, bởi vì PHP thêm thừa kế tĩnh, nó có để đối phó với những trường hợp này góc. Đó là bản chất của các tính năng. Một số ngôn ngữ khác (C#, Java, v.v.) không có vấn đề này, vì chúng áp dụng định nghĩa nghiêm ngặt và chỉ đơn giản là không cho phép abstract static. Để loại bỏ trường hợp góc này và đơn giản hóa động cơ, chúng tôi có thể thực thi quy tắc "tĩnh tĩnh chỉ trong giao diện" này trong tương lai. Do đó, E_STRICT.


Tôi sẽ sử dụng một đại biểu dịch vụ để giải quyết vấn đề:

I have common method I want to use in several classes. This common method relies on a static method that must be defined externally to the common code.

trait MyTrait 
{ 
    public function doSomethingWithSetting() { 
     $service = new MyService($this); 
     return $service->doSomethingWithSetting(); 
    } 
} 

class MyService 
{ 
    public function __construct(MyInterface $object) { 
     $this->object = $object; 
    } 
    public function doSomethingWithSetting() { 
     $setting = $this->object->getSetting(); 
     return $setting; 
    } 
} 

Cảm thấy một chút Rube Goldberg mặc dù. Có lẽ sẽ xem xét động lực cho các số liệu thống kê và xem xét tái cấu trúc chúng.

+0

Tôi đồng ý với phân tích của bạn về 'abstract' so với' static' và ý nghĩa mâu thuẫn của nó trong ngữ cảnh * kế thừa tĩnh *. Tuy nhiên, khi một ký tự * khai báo một phương thức là 'abstract', nó vẫn * có thể được thực hiện trong lớp đang sử dụng — giống như các phương thức' static' được khai báo trong các giao diện có thể được thực hiện trong lớp thực hiện. Vì vậy, mâu thuẫn mà bạn làm nổi bật không phải là viết tắt của các đặc điểm hơn là đối với giao diện, nơi sử dụng như vậy được cho phép. Trích dẫn mã động cơ gây ra lỗi chỉ củng cố rằng đây là một giám sát/lỗi, không phải là nó là một quyết định thiết kế có chủ ý. – eggyal

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