egg*_*yal 12 php oop static traits abstract
使用PHP v5.3中的后期静态绑定,可以static在接口中有用地声明方法; 对于PHP v5.4中的特征,方法可以是static或abstract但不是两者.这似乎是不合逻辑和不一致的.
特别地,假设一个具有特征提供所有实现的接口,静态方法除外; 除非在特征中声明了该方法,否则静态分析器会对特征内的任何引用进行跟踪.但是,在特征中提供具体实现不再强制实现/使用类来提供自己的实现 - 这是危险的; abstract static会是理想的,但不允许.
这个矛盾的解释是什么?你会如何建议解决这个问题?
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 /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
TL; DR:从PHP 7开始,你可以.在此之前,你可以定义abstract static上trait,但内部认为它不好的做法.
严格地说,abstract意味着子类必须实现,并且仅static表示该特定类的代码.总而言之,abstract static意味着"子类必须仅为此特定类实现代码".完全正交的概念.
但是......由于LSB,PHP 5.3+支持静态继承.所以我们实际上打开了这个定义:self采用static的前一个定义,同时static成为"这个特定类或其任何子类的代码".新定义abstract static是"子类必须为此特定类或其任何子类实现代码".这可能会导致一些static严格意义上的人感到困惑.请参阅bug#53081.
是什么让trait如此特别引起此警告?那么,看看实现通知的引擎代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
该代码表示允许的唯一位置abstract static是在interface.它并不是特征所独有的,它的定义是独一无二的abstract static.为什么?好吧,注意我们的定义中有一个小角落的情况:
子类必须为此特定类或其任何子类实现代码
使用此代码:
abstract class Foo {
abstract public static function get();
}
Run Code Online (Sandbox Code Playgroud)
这个定义意味着我应该可以打电话Foo::get.毕竟Foo是一个类(在那里看到关键字"class")并且在严格的定义中,get意味着要在该类中实现Foo.但显然这没有任何意义,因为我们又回到了严格静态的正交性.
如果您在PHP中尝试它,您可以获得唯一的理由响应:
无法调用抽象方法Foo :: get()
因为PHP添加了静态继承,它必须处理这些极端情况.这就是特征的本质.其他一些语言(C#,Java等)没有这个问题,因为它们采用严格的定义并且根本不允许abstract static.为了摆脱这种极端情况,并简化引擎,我们可能在将来强制执行"仅在接口中的抽象静态"规则.因此,E_STRICT.
我会使用服务委托来解决问题:
我有一些常用的方法,我想在几个类中使用.这种常用方法依赖于必须在公共代码外部定义的静态方法.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
感觉有点Rube Goldberg.可能会看静力学的动机,并考虑重构它们.
| 归档时间: |
|
| 查看次数: |
2218 次 |
| 最近记录: |