我有两个班级:
抽象实体,抽象ClassA扩展实体, ClassB扩展ClassA
实体是各种实体的通用类,例如汽车或学生。有一个名为$_entity_name
的静态类变量,它包含ER图中实体的确切类名。
最大的问题:实体无法设置此变量的值,但使用它!所以我必须在实体中定义它,但我不能在ClassA中重新定义它。
ClassA是特殊ORM实体的自动生成的基类(比如说“Student”)。用户应该将此基类子类化以添加自己的业务逻辑。
ClassB由用户创建并扩展ClassA。这是他增加业务逻辑的地方。他不应该触摸$_entity_name
或设置此值。
我看到的唯一方法是:
ClassA定义了一个init()方法,该方法将这些“系统级”实例变量初始化为合理的值。
我希望用户不必考虑调用任何不寻常的东西。我不知道在PHP中是否通常也明确地调用父类的构造函数。但我猜它不是。
问题: A)在实例化类之后调用init()最方便的方法是什么? B)有没有办法以这种方式实现这一点,创建ClassB的用户一定不要考虑调用init()? C)我还有其他选择吗?
答案 0 :(得分:1)
不完全是您问题的答案,但可能是您问题的解决方案:
而不是拥有包含实际类名的属性(这是你想要的,不是吗?)你可以使用get_called_class()(从php 5.3.0开始)获取静态函数的类的名称被称为。
class Entity {
public static function foo() {
echo 'name=', get_called_class(), "\n";
}
}
class ClassA extends Entity { }
class ClassB extends ClassA { }
Entity::foo();
ClassA::foo();
ClassB::foo();
打印
name=Entity
name=ClassA
name=ClassB
答案 1 :(得分:1)
使用parent::__construct()
调用父构造函数实际上很常见。您可以接受以下操作吗?
class B extends A {
function __construct($entity_name = '') {
parent::__construct($entity_name);
}
}
abstract class A extends Entity {
function __construct($entity_name = '') {
parent::__construct($entity_name);
}
}
abstract class Entity {
static $entity_name;
function __construct($entity_name = '') {
self::$entity_name = $entity_name;
}
}
$b = new B('my_name');
答案 2 :(得分:1)
据我了解你的问题:ClassB
是ClassA
的子类,当ClassB
对象被实例化时,你想拥有一个方法(例如{{ 1}})在init()
级别调用,而无需用户在ClassA
代码中编写任何类型的内容。
这就是构造函数的用途。
但是,您暗示由于ClassB
将由您的用户编写,您不希望强迫他/她从ClassB的构造函数中调用ClassB
,这就是您之所以想到的原因使用parent::__construct()
方法,以及为什么要寻找一种方法让init()
以init()
的方式自动调用,我是对的吗?那么,这个怎么样:
__construct()
中添加空init()
方法,用户在撰写ClassA
ClassB
加调用__construct()
中,在ClassA的$_entity_name
(例如初始化__construct()
)中执行您想要执行的操作。$this->init()
设置为__construct()
,以便用户不会重载构造函数。final
方法来为init()
专业人士:您可以让ClassA
完成初始化工作,而无需用户编写任何内容。
缺点:您的用户无法重载ClassA
,但可以重载__construct()
而不是为init()
进行自定义初始化
答案 3 :(得分:0)
VolkerK的答案是正确的 - 但您也可以查看instanceof运算符和get_class()函数。
“遗憾的是,我没有使用PHP类,而是ER图中的实体名称。它有点不同”(openfrog)
然而,这是一个完全不同的问题(假设您无法在实体命名系统中修复此缺陷),两个列表之间的映射条目是明智之举。
您在运行时使用属性的解决方案非常混乱且不灵活。它依赖于隐式映射,其细节分散在整个代码库中,任何非线性启发式都很难维护/调试(例如,如果多个类映射到ERD中的同一实体)。
下进行。
答案 4 :(得分:0)
在ClassB下面,我看到了两种确保ClassA初始化的方法:
指示ClassB的构造函数调用parent::__construct()
或不存在。
创建一个由ClassA调用并由ClassB实现的钩子init
函数。这样,ClassA处理__construct()
和ClassB中ClassA的初始化$this->init()
答案 5 :(得分:0)
这个建议不能被覆盖,以满足您的需求。
Class A{
final public function __construct() {
// do your stuff here
// optionally add something like this:
$rc = new ReflectionClass($this);
if(in_array('init', $rc->getMethods()) {
$this->init();
}
}
如果它没有做你想要的(即你希望从A
派生的类能够使用__construct()
),你应该考虑封装你的类而不是继承它