如果在抽象类中使用了特征,则该特征工作不正确。
请考虑以下代码:
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
延伸并直接使用特征时,我有预期的结果。
我无法在抽象类中找到有关特征的具体用法的任何信息。任何人都可以解释为什么我的代码不能像我期望的那样工作吗?
答案 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