我一直很难找到这个解决方案。我希望你们都能帮助我。
最好用一个例子来描述:
class Parent {
public $nationality;
function __construct($nationality)
{
$this->nationality = $nationality
}
}
class Child extends Parent {
function __construct() {
echo $this->nationality; // hispanic
}
}
// Usage:
$parent = new Parent('hispanic');
$child = new Child();
我希望孩子从已初始化的父级继承属性和方法。
我希望它看起来像这样:
class Tag {
public $class_location;
public $other_tag_specific_info;
public $args;
function __construct($args)
{
$this->args = $args;
}
public function wrap($wrapper) {
...
}
// More public methods Form can use.
}
class Form extends Tag {
function __construct() {
print_r($this->args()) // 0 => 'wahoo', 1 => 'ok'
echo $this->class_location; // "/library/form/form.php"
$this->wrap('form');
}
function __tostring() {
return '<input type = "text" />';
}
}
// Usage:
$tag = new Tag(array('wahoo', 'ok'));
$tag->class_location = "/library/form/form.php";
$tag->other_tag_specific_info = "...";
$form = new Form();
我不喜欢复合图案的原因是它没有 我觉得为什么我会将Tag的实例传递给构造函数 其中一个子类,afterall - Form是一种Tag吗?
谢谢! 马特穆勒
答案 0 :(得分:7)
你想做的事情可以说是糟糕的设计。如果您创建具有不同国籍的多个Parent
实例,然后创建新的Child
实例,会发生什么。这个孩子接受哪个国籍?
为什么不让Child类成为复合体,在构造函数中给它一个父元素?
class Child
{
private $parent;
function __construct($parent)
{
$this->parent = $parent;
}
function getNationality()
{
return $this->parent->nationality;
}
}
然后使用
创建它$parent = new Parent('hispanic');
$child = new Child($parent);
或者使用父母的工厂方法......其余的都取决于你的想象力。
注意:我忽略了这样一个事实:我没有在父类上使用getter获取国籍,也没有为Child提供超类(也许是父级?不是真的有意义) 。这些都是与设计相关的要点,但不在这个问题的范围内。
答案 1 :(得分:3)
我们已经在这里编辑了很多,所以我只想发一个新答案,希望没问题。为了它,我会留下旧答案。
无论如何,我们从最新的例子(Form extends Tag
)开始。
好像你试图模仿某种Builder pattern,所以请耐心等待,让我们举一个简短的例子:
class TagBuilder
{
protected $args;
protected $className;
protected $classLocation;
function __construct()
{
}
public function setClass($file, $class)
{
/* @todo Use reflection maybe to determine if $class is a Tag subclass */
if (file_exists($file))
{
require_once $file; // Or use the autoloader
}
$this->classLocation = $file;
$this->className = $class;
}
/**
* @return Tag the built tag (or tag subclass) instance
*/
public function getTag()
{
$fullyQualifiedClassName = $this->getFullyQualifiedClassName();
$newTag = new $fullyQualifiedClassName($this->args);
$newTag->class_location = $this->classLocation;
return $newTag;
}
protected function getFullyQualifiedClassName()
{
return $this->className;
}
public function setArgs($args)
{
$this->args = $args;
}
}
此外,您必须修改Form构造函数以调用它的parent::__construct($args)
方法,以便传递$args
依赖项。
然后用
运行它$builder = new TagBuilder();
$builder->setClass('/library/form/form.php', 'Form');
$builder->setArgs(array('wahoo', 'ok'));
$form = $builder->getTag();
这是一个很长的例子,它意味着改变了一些OP的API,但是如果我正确地理解了这个问题,那么这就是OP希望在他的应用程序中模仿的所需行为(或者它的一部分)
注意:我知道这不是Builder模式的经典示例,并且getTag
方法对某些纯粹主义者来说可能看起来有些含糊不清。
答案 2 :(得分:0)
这不应被视为良好做法,我只将该功能作为概念证明,以确定是否可以完成。
class MyClass
{
public $_initial = NULL;
public function setInitial($value) {
$this->_initial = $value;
}
}
class MyClass2 extends MyClass
{
private $_reversed = NULL;
private function reverseInitial() {
$this->_reversed = strrev($this->_initial);
}
public function getReversed() {
$this->reverseInitial();
return $this->_reversed;
}
}
$class1 = new MyClass();
$class1->setInitial('rekaB kraM');
inherit($class1,'MyClass','MyClass2');
echo $class1->getReversed();
function inherit(&$object, $oldClassName, $newClassName) {
$oldClass = new ReflectionClass($oldClassName);
$newClass = new ReflectionClass($newClassName);
$wrkSpace = serialize($object);
$wrkTmp = explode('{',$wrkSpace);
$startBlock = array_shift($wrkTmp);
$oldClassProperties = $oldClass->getProperties();
$oldClassPropertyNames = array();
foreach($oldClassProperties as $oldClassProperty) {
if (!$oldClassProperty->isStatic()) {
if ($oldClassProperty->isPrivate()) {
$oldClassPropertyNames[] = "\x0".$oldClassName."\x0".$oldClassProperty->getName();
} elseif($oldClassProperty->isProtected()) {
$oldClassPropertyNames[] = "\x0*\x0".$oldClassProperty->getName();
} else {
$oldClassPropertyNames[] = $oldClassProperty->getName();
}
}
}
$newClassProperties = $newClass->getProperties();
$newClassPropertyValues = $newClass->getDefaultProperties();
$newClassPropertyNames = array();
foreach($newClassProperties as $newClassProperty) {
$propertyName = $newClassProperty->getName();
if (!$newClassProperty->isStatic()) {
if ($newClassProperty->isPrivate()) {
$newPropertyName = "\x0".$newClassName."\x0".$propertyName;
} elseif($newClassProperty->isProtected()) {
$newPropertyName = "\x0*\x0".$propertyName;
} else {
$newPropertyName = $propertyName;
}
$newClassPropertyNames[] = $newPropertyName;
if (isset($newClassPropertyValues[$propertyName])) {
$newClassPropertyValues[$newPropertyName] = $newClassPropertyValues[$propertyName];
}
}
}
$newClassPropertySet = array_diff($newClassPropertyNames,$oldClassPropertyNames);
$toClassName = 'O:'.strlen($newClassName).':"'.$newClassName.'":'.(count($newClassPropertySet)+count($oldClassPropertyNames)).':';
$newPropertyEntries = array_fill_keys($newClassPropertySet,NULL);
foreach($newPropertyEntries as $newPropertyName => $newClassProperty) {
if (isset($newClassPropertyValues[$newPropertyName])) {
$newPropertyEntries[$newPropertyName] = $newClassPropertyValues[$newPropertyName];
}
}
$newPropertyEntries = substr(serialize($newPropertyEntries),4+strlen(count($newClassPropertySet)),-1);
$newSerialized = $toClassName.'{'.$newPropertyEntries.implode('{',$wrkTmp);
$object = unserialize($newSerialized);
}
它并不完全符合您的要求...它需要父类的一个实例并将其更改为子类的实例,但可能会修改它以创建一个新的子项,同时保留父项的完整性
答案 3 :(得分:0)
好的,其他人告诉你这是一个糟糕的设计理念。我打算准不同意见并告诉你,你可能遇到了一个问题领域,基于类的OO层次结构不会对你有所帮助。如果你对这个想法很好奇,我建议你阅读Steve Yegge的“通用设计模式”(http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html)。
但是他有点啰嗦,所以它可能更简洁,同样有趣的是在JavaScript中考虑,你在这里谈论的内容将是微不足道的:
t = new Tag({arg1: val1, arg2: val2})
// ...
// later, when you decide t is a Form
t.prototype = Form.prototype.
这与JavaScript一起工作的原因很大程度上与其基于原型的OO有关,但很多事实上,函数是可以分配给变量并传递的一等值。 PHP有一些动态调用函数的工具(和5.3,用于分配/传递它们)。我想如果你感兴趣并且愿意走出基于类的语言设施之外,你可能会做很多这样的事情。
首先,你会做很多人在没有类的语言中编写面向对象代码的事情:你的“类”可以只是哈希/关联数组(AAs)。
$quasiObj = array('prop1' => $val1, 'prop2' => $val2, '_class' => 'quasiClass');
您的方法可以只是将AA引用作为其第一个参数的函数。
function quasiClass_method1Name($this,$args = array()) {
$this['prop1'] = $args[1] * $args[2];
}
如果您想要与类无关的方法调用,可以使用包装函数:
function method($this,$methodName,$args) {
$fullMethodName = "{$this['_class']}_$methodName";
$fullMethodName($this,$args);
}
// and now, the invocation
method($quasiObj,'method1Name',array(6,7));
在此系统下,当您想要将$quasiObject
从Tag
推广到Form
时,只需更改数组的_class
密钥即可。如果需要进行内部状态更改,可以编写一个函数/方法来处理它。
你确实失去了解释器,为你追踪事物,有些人真的为此烦恼。这些人中的大多数人都在使用Java,因为PHP对他们的播放速度太快而且松散。这是一种动态语言。利用这个事实。 :)