我对 OOP 相当陌生,并且有一个关于如何最好地处理使用一个类名的问题,然后根据传递的参数在内部向该类添加功能。
基本故事是我有一个“项目”类,它接受 2 个参数 $module 和 $id。一些“模块”(但不是全部)将具有“项目”类默认不包含的奇特功能。一些模块还希望覆盖项目类中的一些方法。我的目标是能够从项目类的 __construct 中调用模块的“项目”类扩展。我想有一个单一的“项目”类。
我的第一个想法是在构建项目类时创建模块的项目扩展类的实例,然后,每当我调用项目类中的方法时,我都会检查是否有该模块特定的实例并调用该方法在那个实例上。
例如:
class item {
// Variable where I'll store the instance of the child class
var $child;
// Child class may call up item's constuct, I'll use this to avoid an infinite loop
var $child_initalized;
// Child called, guess we have to keep track of this so we don't get stuck in infite loops either.
var $child_called = 0;
// Example variables
var $id, $name;
function __construct($module,$id) {
if(!$this->child_initialized) {
$this->child_initialized = 1; // So we don't do this again and get stuck in an infite loop
$child_class = __CLASS__.'_'.$module;
if(class_exists($child_class)) {
$this->child = new $child_class($module,$id);
return;
}
}
// do normal class construction stuff here, such as setting $this->id and $this->name
$this->module = $module;
$this->id = $id;
}
// So we can catch child methods not in parent item class
function __call($name,$arguments) {
if($this->child) {
return $this->child->$name();
}
}
function id() {
$this->child_called = 0;
if($this->child) {
$this->child_called = 1;
return $this->child->id();
}
return $this->id;
}
}
class item_photos extends item {
function __construct($module,$id) {
$this->child_initialized = 1;
parent::__construct($module,$id);
}
function id() {
return "photo-".$this->id;
}
function photo_width() {
return 250; // Just some sample value
}
}
$item = new item('photos',123);
print $item->id()."<br />"; // photo-123
print $item->photo_width()."<br />"; // 250
无论如何,这只是一个简单的例子。但是,我的方法似乎……嗯,错了。有什么更好的方法来实现这一点,还是我应该重新考虑如何构建所有内容?您可以提供的任何建议或想法都会很棒。
/ * ** * ** * ** * *编辑* ** * ** * ** * * /
澄清一下,我的目标实际上是能够调用一个类(在我的示例中为“项目”),并且基于传递给它的一个或多个参数,能够基于这些参数动态加载更多功能(在我的示例中,它是 $module)。但是这种额外的功能并不总是存在(所以我不能总是调用 new item_photos 而不是 new item())。
这是一个更新的示例。在代码末尾调用 $item = new item('videos',456) 是某些模块没有额外功能的示例。
class item {
// Variable where I'll store the instance of the child class
public $child;
// Child class may call up item's constuct, I'll use this to avoid an infinite loop. Also to avoid when calling child class in methods.
public $child_initalized;
// Example variables
public $module, $id, $name;
function __construct($module,$id) {
if(!$this->child_initialized) {
$child_class = __CLASS__.'_'.$module;
if(class_exists($child_class)) {
$this->child = new $child_class($module,$id);
return;
}
}
// do normal class construction stuff here, such as setting $this->id and $this->name
$this->module = $module;
$this->id = $id;
}
// So we can catch child methods not in parent item class
function __call($name,$arguments) {
if($this->child) {
return $this->child->$name();
}
}
function id() {
$this->child_initalized = 0;
if($this->child) {
$this->child_initalized = 1;
return $this->child->id();
}
return $this->id;
}
}
class item_photos extends item {
function __construct($module,$id) {
$this->child_initialized = 1;
parent::__construct($module,$id);
}
function id() {
return "photo-".$this->id;
}
function photo_width() {
return 250; // Just some sample value
}
}
$item = new item('photos',123);
print "photo id: ".$item->id()."<br />"; // photo-123
print "photo size: ".$item->photo_width()."<br />"; // 250
$item = new item('videos',456);
print "video id: ".$item->id()."<br />"; // 456
print "video size: ".$item->photo_width()."<br />"; // nothing (that method doesn't exist here)
/ * ** * ** * ** *编辑2 * ** * ** * *** /
还是有点挣扎。我研究了抽象工厂,它们似乎不起作用。如果我理解正确,我必须在抽象类中声明所有方法,这很棘手,因为模块会扩展项目类,所以我不会知道所有方法。另外,我似乎不得不调用“item_photos”或“item_videos”,而不仅仅是“item”,这是我试图避免的。更不用说在我的示例中 item_videos 甚至不存在。
鉴于我的目标是调用一个类,然后在该类 __construct 中确定是否需要基于 $module 包含任何额外的功能,我想出了这个。
基本上,“item”类的内容被移至新的“item_core”。旧的项目类现在只决定使用哪个类,要么是模块的项目类(如果存在)(例如:item_photos),要么是核心项目类(item_core)。在初始化其中一个类之后,我存储实例并在调用方法时使用它(通过 __call,让我知道为什么使用 __call 不好)。
class item {
// Instance of the core class or module class
private $instance;
function __construct($module,$id) {
$class = __CLASS__;
$class_core = $class.'_core';
$class_module = $class.'_'.$module;
// Module class
if(class_exists($class_module)) $this->instance = new $class_module($module,$id);
// Core class
else $this->instance = new $class_core($module,$id);
}
// Catch all calls, redirect accordingly
function __call($name,$arguments) {
if($this->instance) {
if(method_exists($this->instance,$name)) return $this->instance->$name();
}
}
}
class item_core {
public $module, $id;
function __construct($module,$id) {
$this->module = $module;
$this->id = $id;
}
function id() {
return $this->id;
}
}
class item_photos extends item_core {
function __construct($module,$id) {
parent::__construct($module,$id);
}
function id() {
return "photo-".$this->id;
}
function photo_width() {
return 250; // Just some sample value
}
}
$item = new item('photos',123);
print "photo id: ".$item->id()."<br />"; // photo-123
print "photo size: ".$item->photo_width()."<br />"; // 250
$item = new item('videos',456);
print "video id: ".$item->id()."<br />"; // 456
print "video size: ".$item->photo_width()."<br />"; // nothing (that method doesn't exist in the videos module)
任何人都认为这有任何问题或无论如何要改进它?对我来说似乎还是有点不对劲。
/ * ***编辑 3** * **** /
好吧,在我看来,我想做的事情是能够返回与我调用的不同的实例。因此,调用 new item($module,$id);,但如果 $module == photos(在我的示例中)我想返回 new item_photos($module,$id); 的实例。到目前为止,我提出了两种可能的解决方案。
首先是我在编辑 2 中概述的内容(见上文)。
第二种选择是简单地调用一个函数(可能是'item')并在那里返回正确的对象实例(因为函数可以返回您想要的任何对象实例,而类构造函数只返回其自己的类的实例)。所以(基本示例):
function item($module,$id) {
$class_module = 'item_'.$module;
// Module class
if(class_exists($class_module)) return new $class_module($module,$id);
// Core class
else return new item($module,$id);
}
class item{..}
class item_photos{..}
$item = item('photos',123);
print $item->id(); // photo-123
不确定我喜欢混合函数/类,但它很简单。
想法?