Let*_*eto 79 php oop interface traits
我想知道为什么PHP Trait(PHP 5.4)无法实现接口.
从user1460043的answer => ...更新不能要求使用它来实现特定接口的类
我明白这可能是显而易见的,因为人们可以认为如果一个人Class A正在使用一个Trait T正在实施的interface I,那么Class A应该是直接实现的interface I(这不是真的,因为Class A可以重命名特征方法).
在我的例子中,我的特性是从使用特征的类实现的接口调用方法.
该特征实际上是接口的一些方法的实现.所以,我想在代码中"设计"每个想要使用我的特性的类都必须实现该接口.这将允许Trait使用接口定义的类方法,并确保它们存在于类中.
Dan*_*ack 91
真正的简短版本更简单,因为你不能.这不是Traits的工作方式.
当您use SomeTrait;使用PHP 编写时,您(有效地)告诉编译器将Trait中的代码复制并粘贴到正在使用它的类中.
因为use SomeTrait;它在类中,所以它不能添加implements SomeInterface到类中,因为它必须在类之外.
"为什么不是PHP中的Traits类型?"
因为它们无法实例化.Traits实际上只是一种语言构造(告诉编译器将特征代码复制并粘贴到此类中),而不是代码可以引用的对象或类型.
所以,我想在代码中"设计"每个想要使用我的特性的类都必须实现该接口.
可以使用抽象类对use特征强制执行,然后从中扩展类.
interface SomeInterface{
public function someInterfaceFunction();
}
trait SomeTrait {
function sayHello(){
echo "Hello my secret is ".static::$secret;
}
}
abstract class AbstractClass implements SomeInterface{
use SomeTrait;
}
class TestClass extends AbstractClass {
static public $secret = 12345;
//function someInterfaceFunction(){
//Trying to instantiate this class without this function uncommented will throw an error
//Fatal error: Class TestClass contains 1 abstract method and must therefore be
//declared abstract or implement the remaining methods (SomeInterface::doSomething)
//}
}
$test = new TestClass();
$test->sayHello();
Run Code Online (Sandbox Code Playgroud)
但是 - 如果你确实需要强制使用任何使用Trait的类具有特定方法,我认为你可能正在使用特征,你应该首先使用抽象类.
或者说你的逻辑是错误的.您的意图是要求实现接口的类具有某些功能,而不是如果它们具有某些功能,则必须将它们声明为实现接口.
编辑
实际上,您可以在Traits中定义抽象函数以强制类实现该方法.例如
trait LoggerTrait {
public function debug($message, array $context = array()) {
$this->log('debug', $message, $context);
}
abstract public function log($level, $message, array $context = array());
}
Run Code Online (Sandbox Code Playgroud)
然而,这仍然不允许您在特征中实现接口,并且仍然闻起来像一个糟糕的设计,因为接口比定义类需要实现的合同的特性要好得多.
Ili*_*ija 23
有一个RFC:带有接口的Traits建议将以下内容添加到该语言中:
trait SearchItem implements SearchItemInterface
{
...
}
Run Code Online (Sandbox Code Playgroud)
接口所需的方法既可以由trait实现,也可以声明为abstract,在这种情况下,期望使用trait的类实现它.
该语言目前不支持此功能,但它正在考虑之中(RFC的当前状态是:在讨论中).
[...]在代码中"设计"每个想要使用我的特征的类都必须实现该接口.这将允许Trait使用接口定义的类方法,并确保它们存在于类中.
这听起来很合理,我不会说你的设计有任何问题.有人提出了这个想法的特点,请看第二点:
- 特征提供了一组实现行为的方法.
- 特征需要一组方法作为所提供行为的参数.
- [...]
所以说你想要一个特性需要一个接口而不是"实现"它可能更合适.
我没有看到为什么不应该让这个"trait需要(它的消费者类实现)PHP中的接口"功能,但目前它似乎缺失了.
正如@Danack在他的回答中指出的那样,你可以在特征中使用抽象函数来从使用特征的类中"要求"它们.不幸的是,你不能用私人功能这样做.
小智 5
我同意@Danack 的回应,但我会补充一点。
真正简短的版本更简单,因为你做不到。这不是 Traits 的工作原理。
我只能想到少数情况,在这些情况下,您的要求是必要的,并且作为设计问题比作为语言失败更明显。想象一下有一个这样的界面:
interface Weaponize
{
public function hasAmmunition();
public function pullTrigger();
public function fire();
public function recharge();
}
Run Code Online (Sandbox Code Playgroud)
创建了一个特征,它实现了接口中定义的函数之一,但在此过程中使用了接口也定义的其他函数,容易出现错误:如果使用该功能的类没有实现该接口,则所有内容都无法拉取该功能。扳机
trait Triggerable
{
public function pullTrigger()
{
if ($this->hasAmmunition()) {
$this->fire();
}
}
}
class Warrior
{
use Triggerable;
}
Run Code Online (Sandbox Code Playgroud)
一个简单的解决方案就是强制使用该特征的类也实现这些功能:
trait Triggerable
{
public abstract function hasAmmunition();
public abstract function fire();
public function pullTrigger()
{
if ($this->hasAmmunition()) {
$this->fire();
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,特征并不完全依赖于接口,而是实现其功能之一的建议,因为当使用特征时时,类将要求实现抽象方法。
interface Weaponize
{
public function hasAmmunition();
public function pullTrigger();
public function fire();
public function recharge();
}
trait Triggerable
{
public abstract function hasAmmunition();
public abstract function fire();
public function pullTrigger()
{
if ($this->hasAmmunition()) {
$this->fire();
}
}
}
class Warrior implements Weaponize
{
use Triggerable;
public function hasAmmunition()
{
// TODO: Implement hasAmmunition() method.
}
public function fire()
{
// TODO: Implement fire() method.
}
public function recharge()
{
// TODO: Implement recharge() method.
}
}
Run Code Online (Sandbox Code Playgroud)
请原谅我的英语