
在php中,当你使用 new classname() 创建一个对象时,系统会自动寻找并执行该类的构造函数。构造函数是一个特殊的方法,通常命名为 __construct,它的主要作用是在对象被创建时初始化对象的属性。
问题分析: 在原始代码中,Patient 类定义了一个名为 record 的方法来设置属性:
class Patient{
// ...
public function record($name, $age, $gender){
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
}
// ...
}然而,在 Clinic 类的 assignPatient 方法中,却尝试直接使用 new Patient($name, $age, $gender) 来创建 Patient 对象:
class Clinic extends Patient{
// ...
public function assignPatient($name, $age, $gender){
$this->patients[] = new Patient($name, $age, $gender); // 问题所在
}
// ...
}由于 Patient 类没有定义 __construct 方法,PHP 在执行 new Patient(...) 时,并不会将传入的参数自动赋值给对象的属性。因此,Patient 对象的 $name, $age, $gender 属性保持未初始化状态,导致后续访问时可能得到 NULL 值。
解决方案: 将 record 方法重命名为 __construct,使其成为 Patient 类的构造函数。这样,在创建 Patient 对象时,传入的参数就能正确地初始化对象的属性。
<?php
class Patient{
private $name;
private $age;
private $gender;
// 将 record 方法改为构造函数 __construct
public function __construct($name, $age, $gender){
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
}
public function getName(){
return $this->name;
}
public function getAge(){
return $this->age;
}
public function getGender(){
return $this->gender;
}
}
?>在面向对象设计中,选择正确的类关系是构建可维护和可扩展代码的关键。主要有两种常见的关系:
问题分析: 原始代码中,Clinic 类通过 extends Patient 继承了 Patient 类:
class Clinic extends Patient{
// ...
}从业务逻辑上看,“诊所是一个病人” (Clinic is a Patient) 这种说法是不合理的。一个诊所不应该拥有病人的属性(如姓名、年龄、性别),也不应该执行病人的行为。相反,一个诊所应该“拥有”或“管理”多个病人。这种情况下,Clinic 和 Patient 之间是“has-a”关系,即“诊所拥有病人列表”。
立即学习“PHP免费学习笔记(深入)”;
不恰当的继承不仅会造成语义上的混淆,还可能引入不必要的复杂性或限制。
解决方案: 移除 Clinic 类对 Patient 类的继承。Clinic 类应该通过组合的方式来管理 Patient 对象,即在其内部维护一个 Patient 对象的集合。
<?php
// ... Patient 类定义不变 ...
// Clinic 类不再继承 Patient 类
class Clinic {
private $patients = []; // 诊所拥有一个病人列表
public function getPatients(){
return $this->patients;
}
public function assignPatient($name, $age, $gender){
// 使用修正后的 Patient 构造函数创建对象
$this->patients[] = new Patient($name, $age, $gender);
}
public function deletePatient($index){
unset($this->patients[$index]);
// 注意:unset 只是移除元素,不会重置数组索引。
// 如果需要连续索引,可以使用 array_values($this->patients)
}
}
?>结合上述两点修正,最终的代码如下:
<?php
class Patient{
private $name;
private $age;
private $gender;
// 构造函数,用于初始化 Patient 对象
public function __construct($name, $age, $gender){
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
}
public function getName(){
return $this->name;
}
public function getAge(){
return $this->age;
}
public function getGender(){
return $this->gender;
}
}
// Clinic 类通过组合管理 Patient 对象
class Clinic {
private $patients = []; // 存储 Patient 对象的数组
public function getPatients(){
return $this->patients;
}
public function assignPatient($name, $age, $gender){
// 创建 Patient 对象并添加到列表中
$this->patients[] = new Patient($name, $age, $gender);
}
public function deletePatient($index){
// 删除指定索引的 Patient 对象
unset($this->patients[$index]);
}
}
// 实例化 Clinic 对象
$clinic = new Clinic();
// 添加病人
$clinic->assignPatient("Patrick star",18,"Male");
$clinic->assignPatient("SpongeBob Squarepants",17,"Male");
$clinic->assignPatient("Eugene Krab",28,"Male");
// 删除索引为 1 的病人(SpongeBob Squarepants)
$clinic->deletePatient(1);
// 打印当前诊所中的病人列表
print_r($clinic->getPatients());
?>运行结果:
Array
(
[0] => Patient Object
(
[name:Patient:private] => Patrick star
[age:Patient:private] => 18
[gender:Patient:private] => Male
)
[2] => Patient Object
(
[name:Patient:private] => Eugene Krab
[age:Patient:private] => 28
[gender:Patient:private] => Male
)
)从输出可以看出,Patient 对象的属性被正确初始化,并且 SpongeBob Squarepants (索引 1) 已被成功删除,解决了最初的 NULL 值问题。
通过理解和正确应用构造函数以及恰当选择类之间的关系,开发者可以编写出更加健壮、易于理解和维护的PHP面向对象代码。
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号