为什么PHP Trait不能实现接口?

2022-08-30 07:58:34

我想知道为什么PHP Trait(PHP 5.4)不能实现接口。

从 user1460043 的答案更新 = > ...不能要求使用它来实现特定接口的类

我知道这可能是显而易见的,因为人们可能会认为,如果a正在使用a,那么它正在实现一个,那么应该不直接地实现(这不是真的,因为可以重命名特质方法)。Class ATrait Tinterface IClass Ainterface IClass A

在我的例子中,我的特质是从使用该特质的类实现的接口调用方法。

该特征实际上是接口的某些方法的实现。所以,我想在代码中“设计”每个想要使用我的特质的类都必须实现接口。这将允许 Trait 使用接口定义的类方法,并确保它们存在于类中。


答案 1

真正简短的版本更简单,因为你不能。这不是特质的工作方式。

当你用PHP编写时,你(有效地)告诉编译器将代码从Trait复制并粘贴到使用它的类中。use SomeTrait;

因为 位于类内部,所以它不能添加到类中,因为它必须在类外部。use SomeTrait;implements SomeInterface

“为什么PHP中的Traits不是类型?

因为它们无法实例化。Traits 实际上只是一种语言构造(告诉编译器将 trait 代码复制并粘贴到此类中),而不是代码可以引用的对象或类型。

所以,我想在代码中“设计”每个想要使用我的特质的类都必须实现接口。

这可以通过使用抽象类来强制执行,然后从中扩展类。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();

但是 - 如果你确实需要强制任何使用Tratraits的类都有一个特定的方法,我认为你可能正在使用你本来应该是抽象类的特征。

或者说你的逻辑是错误的。你打算要求实现接口的类具有某些函数,而不是要求如果它们具有某些函数,它们必须将自己声明为实现接口。

编辑

实际上,您可以在 Traits 中定义抽象函数,以强制类实现该方法。例如:

trait LoggerTrait {

    public function debug($message, array $context = array()) {
        $this->log('debug', $message, $context);
    }

    abstract public function log($level, $message, array $context = array());
}

然而,这仍然不允许你在特质中实现接口,并且仍然闻起来像一个糟糕的设计,因为在定义类需要履行的契约时,接口比特质要好得多。


答案 2

有一个RFC:具有接口的特征建议将以下内容添加到语言中:

trait SearchItem implements SearchItemInterface
{
    ...
}

接口所需的方法可以由 trait 实现,也可以声明为抽象,在这种情况下,期望使用该 trait 的类实现它。

该语言目前不支持此功能,但正在考虑中(RFC 的当前状态为:正在讨论中)。


推荐