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.
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
@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
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