PHP继承疑问:实例化Song类后能否访问Artist类的艺术家名称?
嘿,我完全懂你现在的困惑——刚啃OOP继承这块的时候,很容易把「类的继承关系」和「对象实例之间的关联」搞混,我来帮你把这层窗户纸捅破:
理清核心问题:为什么Song实例访问不到你创建的Artist实例的名称?
1. 先纠正对继承的小误解
你说“继承可让子类访问父类的属性和方法”这个大方向是对的,但这里的关键点是:继承是「类层面」的属性/方法复用,不是「实例层面」的数据共享。
换句话说,子类继承的是父类的“模板”——子类实例会拥有父类定义的属性和方法,但这些属性是属于子类实例自己的,和你之前单独创建的那个Artist实例的属性完全没关系。举个直观的代码例子:
// 父类Artist class Artist { public $name; public function __construct($name) { $this->name = $name; } } // 假设你让Song继承Artist(这里其实逻辑上不合理,后面会说) class Song extends Artist {} // 实例化Artist得到"Joji Miller" $artist = new Artist("Joji Miller"); // 实例化Song $song = new Song(); echo $song->name; // 这里会输出空!因为$song是独立的实例,它的name和$artist的name毫无关联
2. 你真正需要的是「对象关联(组合)」,不是继承
从业务逻辑来看,Song和Artist是「has-a」关系(一首歌属于某个艺术家),这时候用组合才是正确的做法——把已经创建好的Artist实例,作为Song类的一个属性存进去,而不是用继承。
正确的写法应该是这样:
class Artist { public $name; public function __construct($name) { $this->name = $name; } } class Song { public $artist; // 用来存储关联的Artist实例 public $title; public function __construct($title, Artist $artist) { $this->title = $title; $this->artist = $artist; // 把已有的Artist实例关联到当前Song里 } // 也可以封装个方法快速获取艺术家名称 public function getArtistName() { return $this->artist->name; } } // 先创建Artist实例 $joji = new Artist("Joji Miller"); // 创建Song时传入关联的Artist对象 $slowDancing = new Song("Slow Dancing in the Dark", $joji); // 现在就能顺利访问艺术家名称了! echo $slowDancing->artist->name; // 输出 "Joji Miller" // 或者用封装好的方法 echo $slowDancing->getArtistName(); // 同样输出 "Joji Miller"
3. 结合你用过的CodeIgniter再理解下
你之前用CodeIgniter时,控制器继承CI_Controller,这是合理的「is-a」关系(你的控制器是一种CI_Controller)。每个控制器实例都会继承父类的$this->load、$this->input等方法/属性,但每个请求对应的控制器实例都是独立的——它们之间不会共享数据,这和你遇到的情况本质是一样的:继承给的是类的能力,不是实例的数据。
最后总结下
- 「is-a」关系(比如SoloArtist是一种Artist)用继承;
- 「has-a」关系(比如Song属于某个Artist)用对象关联(组合);
- 继承不会让不同实例共享数据,每个实例的属性都是独立的。
内容的提问来源于stack exchange,提问作者Dan Angelo Alcanar
相关产品推荐
相关产品推荐

