好的,这不仅仅是一个PHP问题,但我在PHP中遇到了这个问题,所以我将在PHP中发布这个例子。
示例:
我有三个课程,比如data_abstract,person和student。现在,我有一个与每个对象相关的数据数组。
class person extends data_abstract { protected $data; //name, gender, etc } class student extends person { protected $data; //student_id, etc }
现在,假设每个“data”属性都来自数据库表,例如table_person,table_student。
实例化后,我们将通过get_class()函数解析类名,并从相关表中获取数据。
class data_abstract { public function __construct() { $name = get_class($this); $table = 'table_' . $name; $this->data = DB->query('SELECT * FROM ' . $table); //whatever DB constant is, //I'm just trying to get all rows of data from the related table. } }
好的,现在问题是,当我通过$ student = new student()实例化学生时;构造函数将从table_student获取数据并将其放入$ student->数据中,但是我将无法从table_person获取数据并将这两组数据放入一个对象中。
通过扩展另一个类,我们可以扩展和定制所有方法(函数)(通过多态),但扩展每个对象级别的属性/属性似乎很难,至少没有一些手动构建。
抽象级别有没有办法实现这个目标?
(感谢阅读,希望我能让问题更清楚。)
答案 0 :(得分:3)
如果我理解得很好:
在这种情况下,您应该外部化$ data feed,这样您就可以重载数据。我编辑了,现在我们有一个工作的例子:
class DataAbstract // Using caps is much better for class name
{
public function __construct()
{
$this->loadData();
}
public function loadData()
{
// don't use getclass on $this or $this will refer to the children
$table = 'table_' . __CLASS__;
$this->data = array($table);
}
}
class Person extends DataAbstract
{
public function __construct()
{
parent::__construct();
}
public function loadData()
{
parent::loadData();
$table = 'table_' . __CLASS__;
$this->data = array_merge($this->data, array($table));
}
}
class Student extends Person
{
public function __construct()
{
parent::__construct();
}
public function loadData()
{
parent::loadData();
$table = 'table_' . __CLASS__;
$this->data = array_merge($this->data, array($table));
}
}
$c = new student();
print_r($c->data);
输出
Array
(
[0] => table_DataAbstract
[1] => table_Person
[2] => table_Student
)
顺便说一句,请记住,PHP得到了内省,它允许您动态设置所需的字段:使用大型数组可能更清晰。
如果您知道所有字段名称,则可以执行类似
的操作function populate($data) // get the array from the DB
{
$fieldList = get_class_vars($this); // get the filed list
foreach ($fieldList as $key => $value)
{
$this->$key = $data[$key]; // feed the field one by one with the array
}
}
答案 1 :(得分:1)
就个人而言,我会将数据库加载类放在一个受保护的方法中,该方法接受属性$tablename
,并加载所有数据。然后在类的构造函数中手动调用它,以及父类。
class Person
{
public function __construct() {
$this - > loadData("Person");
}
}
Class Student extends Person
{
public function __construct() {
parent::__construct();
$this - > loadData("Student");
}
}
现在,当您构建Student
时,Student
和Person
的数据都会被加载。如果使用array_merge()
,则2个数据阵列将合并为一个。
这是风格问题;一些人会批评这一点,说你现在重复两次 - 更多的工作重构 - 但我会说你正在将类名和接口与数据库设计脱钩(一件好事)和父调用,代码是现在更多的是OO。