为什么特质在抽象类中不起作用?

时间:2018-03-11 17:59:21

标签: php abstract-class traits

如果在抽象类中使用了特征,则该特征工作不正确。

请考虑以下代码:

abstract class C {
    static $class;

    use T;
}

trait T {
    static $mockClass;

    public function __construct() {
        static::$mockClass = static::$class;
    }
}

class A extends C{
    static $class = 'A1';
}

class B extends C{
    static $class = 'B1';
}

$a = new A();
$b = new B();

dump($a::$mockClass); // B1, should be A1
dump($b::$mockClass); // B1, should be B1

在转发mockClass时,我们在两种情况下都有B1。为什么?当我没有从C延伸并直接使用特征时,我有预期的结果。

我无法在抽象类中找到有关特征的具体用法的任何信息。任何人都可以解释为什么我的代码不能像我期望的那样工作吗?

2 个答案:

答案 0 :(得分:1)

正如评论中所提到的,这更多地与static属性有关。静态属性在类的所有实例之间共享(这就是为什么你不能使用$this来引用它们。)因为你的所有类都扩展了C,它们都将共享相同的{{{ 1}}。您会发现所有实例都将最后一个值分配给$mockClass,如果您交换了两个对象$mockClass$a的创建,则两者都会显示$b

使用普通属性的工作版本......

A1

我想补充一点,在特征中使用构造函数肯定会在某些时候引起问题,所以不是开始使用的最佳方法。

更新: 如前所述,如果将trait T { public $mockClass; public function __construct() { $this->mockClass = static::$class; } } abstract class C { static $class; use T; } class A extends C{ static $class = 'A1'; } class B extends C{ static $class = 'B1'; } $a = new A(); $b = new B(); print_r($a->mockClass); // A1, should be A1 print_r($b->mockClass); // B1, should be B1 移动到派生类A&中,则所有类都扩展使用特征T的C.乙...

use T;

仍然不认为这是对特质的良好运用,但我会把它留给你。

答案 1 :(得分:1)

您的代码无法按预期运行的原因是:

在实例化A:$a = new A();期间,

执行这部分代码:static::$mockClass = static::$class;

其中static::$class的值为'A1',显然来自班级A但是

直到$mockClass未在子类中重新声明,它位于类C中。

即使您使用关键字static:: ,因为,负责实例化的代码static::$mockClass = static::$class;的特定部分也会在类C中执行。

你似乎不理解的最重要的部分是:在PHP(我不确定其他语言)中,当在A类中定义代码的某些部分并且B类继承自A类并且具有附加部分时代码 - 如果你在B上执行代码的任何部分,但是没有在B中重新定义但是来自A - 你可以想象代码实际上是在它来自的父类A中执行的。

因此,当在B实例化期间下次再次执行代码static::$mockClass = static::$class;时,static::$class现在的值为'B1',但会覆盖static::$class的值仍然位于C 1}}。

这稍微改变了您的代码示例应该让您了解正在发生的事情(并且它按预期工作):

abstract class C {
    static $class;

    use T;
}

trait T {
    static $mockClass;

    public function __construct() {
        static::$mockClass = static::$class;
    }
}

class A extends C{
    static $class = 'A1';
    static $mockClass;
}

class B extends C{
    static $class = 'B1';
    static $mockClass;
}

$a = new A();
$b = new B();

var_dump($a::$mockClass); // A1, should be A1
var_dump($b::$mockClass); // B1, should be B1