我对 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
不确定我喜欢混合函数/类,但它很简单。
想法?