我想知道为什么php特性(php 5.4)不能实现接口。
从user1460043的答案更新=>…不能要求使用它来实现特定接口的类
我理解这是显而易见的,因为人们可以认为,如果一个Class A使用一个Trait T来实现一个interface I,那么Class A就应该不直接地实现interface I(这不是真的,因为Class A可以重命名特征方法)。
在我的例子中,我的特性是从使用特性的类实现的接口调用方法。
这个特性实际上是接口的一些方法的实现。所以,我想在代码中"设计"每个想要使用我的特性的类都必须实现接口。这将允许特性使用由接口定义的类方法,并确保它们存在于类中。
请参阅stackoverflow.com/questions/9205083/php-traits-vs-interfaces
这不是重点,我知道特性和界面之间的区别。
也许有技术上的原因,但我想知道你为什么要这样做?你不能实例化一个特性,所以让它实现一个接口并不能给你任何类型化的好处。如果您希望像您所说的那样,强制使用特性来实现接口的类,那么您会想知道(抽象的)基类是否更合适。
你说得对,我可以在任何地方使用抽象类,但我正在将代码更新为trait,它避免了我在简单继承中遇到的问题,这就是我使用trait的原因。因此,在这种情况下,这是可能的,但在其他一些情况下,这是不可能的。
或者更简单地说:为什么特性类型不在PHP中?
真正简短的版本更简单,因为你不能。这不是特征的工作方式。
当你用PHP编写use SomeTrait;时,你(有效地)告诉编译器将代码从特性复制并粘贴到正在使用的类中。
因为use SomeTrait;在类内,所以不能将implements SomeInterface添加到类内,因为它必须在类外。
"why aren't Traits types in PHP?"
因为它们不能被实例化。特性实际上只是一种语言构造(告诉编译器将特性代码复制并粘贴到这个类中),而不是代码可以引用的对象或类型。
So, i want to"design" in the code that every class that want to use
my trait have to implement the interface.
它可以使用抽象类来强制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();
但是-如果您确实需要强制任何使用特性的类具有特定的方法,那么我认为您可能正在使用特性,因为您首先应该是抽象类。
或者你的逻辑错误。您的目的是要求实现接口的类具有某些函数,而不是如果它们具有某些函数,那么它们必须声明自己是实现接口的。
编辑
实际上,您可以在特性内部定义抽象函数来强制类实现该方法。例如
trait LoggerTrait {
public function debug($message, array $context = array()) {
$this->log('debug', $message, $context);
}
abstract public function log($level, $message, array $context = array());
}
然而,这仍然不允许您在特性中实现接口,而且仍然有一种糟糕的设计味道,因为在定义类需要实现的契约时,接口比特性要好得多。
那么,我有一个人工类,这个类是根据作业抽象成子类的,但是这些作业中的许多共享特性,这些特性最好用共享代码实现(例如,秘书和程序员都需要type方法)。你能想一想,如果没有特征,这是如何实现的吗?
@scragar你应该在programmers.stackexchange.com上问这个问题,但简短的版本是,我将"human"和多个"jobs"组合成一个"workinghuman"类。
再一个。如果接口定义了一些意识契约,并且该契约对于大多数实现都是通用的。但是这些实现有自己的类型3。类似于带有containerawareinterface的命令。但康曼德有其特定的使用领域。所以每次我需要容器意识的时候我都需要重复我自己,但是如果我使用这个特性,我就不能为特定的接口定义它自己的契约。也许核心开发人员应该考虑Go类型的接口(例如结构类型)?
这真的很奇怪,因为实际上我和我的同事只在我们想要共享实现接口但来自不同祖先的几个类所需的代码时才使用特性。也没有合理的解释为什么编译器可以改变类内的代码,但不能改变这个类实现的接口。…这只是一个"缺失"的功能…因为你不能"解释得最好"
我认为PHP核心开发人员应该研究一些scala,其中特性被认为是成熟的类型…我觉得很遗憾的是,PHP逐渐想要改进其输入系统,但没有考虑到现有的良好工作的实现。
有一个RFC:带有接口的特性建议在语言中添加以下内容:
trait SearchItem implements SearchItemInterface
{
...
}
接口所需的方法可以由特性实现,也可以声明为抽象的,在这种情况下,使用特性的类应该实现它。
该语言目前不支持该功能,但正在考虑该功能(RFC的当前状态为:讨论中)。
[...] to"design" in the code that every class that want to use my trait
have to implement the interface. That would allow the Trait to use class methods
defined by the interface and be sure they are existing in the class.
这听起来很合理,我不会说你的设计有什么问题。考虑到这一想法,我们提出了一些特点,请看下面的第二点:
A trait provides a set of methods that implement behaviour.
A trait requires a set of methods that serve as parameters for the provided behaviour.
[...]
SCH?RLI等人,《特征:可组合的行为单位》,Ecoop'2003,LNCS 2743,第248-274页,Springer Verlag,2003,第2页。
所以说您希望一个特性需要一个接口,而不是"实现"它可能更合适。
我不明白为什么在PHP中不可能有这样的"特性需要(它的消费者类实现)一个接口"特性,但是目前它似乎已经丢失了。
正如@danack在他的答案中指出的,您可以使用特性中的抽象函数从使用特性的类中"要求"它们。不幸的是,您不能用私有函数来实现这一点。
我同意@danack的回复,不过我会补充一点。
The really short version is simpler because you can't. That's not how Traits work.
我只能在少数情况下认为您请求的内容是必要的,并且比语言故障更明显是一个设计问题,想象一下有这样一个接口:
interface Weaponize
{
public function hasAmmunition();
public function pullTrigger();
public function fire();
public function recharge();
}
已经创建了一个实现接口中定义的一个函数的特性,但在进程中使用了接口也定义的其他函数,这很容易出错,如果使用该特性的类不实现接口,则所有操作都无法拉动触发器。
trait Triggerable
{
public function pullTrigger()
{
if ($this->hasAmmunition()) {
$this->fire();
}
}
}
class Warrior
{
use Triggerable;
}
一个简单的解决方案就是简单地强制使用特性的类实现这些函数:
trait Triggerable
{
public abstract function hasAmmunition();
public abstract function fire();
public function pullTrigger()
{
if ($this->hasAmmunition()) {
$this->fire();
}
}
}
所以这个特性并不完全依赖于接口,而是一个实现它的一个函数的建议,因为当使用这个特性时,类将要求实现抽象方法。最终设计
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.
}
}
对不起,英语