让一个子级在PHP中扩展已初始化的父级
我一直很难想出解决这个问题的办法。我希望你们都能帮助我 最好用一个例子来描述:让一个子级在PHP中扩展已初始化的父级,php,inheritance,oop,Php,Inheritance,Oop,我一直很难想出解决这个问题的办法。我希望你们都能帮助我 最好用一个例子来描述: class Parent { public $nationality; function __construct($nationality) { $this->nationality = $nationality } } class Child extends Parent { function __construct() { echo
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();
我希望子对象从已初始化的父对象继承属性和方法
编辑:谢谢大家的回复-让我给你一些背景。我正在尝试制作一个模板系统。我有两个类——比如Tag.php和Form.php 我希望它看起来像这样:
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();
class标签{
公共$class_位置;
公共$other_标签_特定_信息;
公费$args;
函数构造($args)
{
$this->args=$args;
}
公共函数包装($wrapper){
...
}
//表单可以使用更多的公共方法。
}
类窗体扩展标记{
函数_u构造(){
打印($this->args())//0=>'wahoo',1=>'ok'
echo$this->class_location;//“/library/form/form.php”
$this->wrap('form');
}
函数u_tostring(){
返回“”;
}
}
//用法:
$tag=新标记(数组('wahoo','ok'));
$tag->class_location=“/library/form/form.php”;
$tag->other_tag_specific_info=“…”;
$form=新表单();
我不喜欢复合图案的原因是它不适合
我能感觉到为什么我要将标记的实例传递给构造函数吗
在它的一个子类中,Form毕竟是一种标记,对吗
谢谢!
马特·穆勒(Matt Mueller)你想做的可以说是糟糕的设计。如果创建多个具有不同国籍的
父实例,然后创建一个新的子实例,会发生什么情况。那么这个孩子是哪国人呢
为什么不让子类成为复合类,在构造函数中给它一个父类呢
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提供超类(可能是父类?没有真正意义)。这些都是与设计相关的要点,但不在这个问题的范围内。这不应该被认为是好的做法,我只是将函数作为概念证明来编写,看看是否可以完成
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);
}
它不能完全满足你的要求。。。它接受父类的一个实例并将其更改为子类的一个实例,但可能会对其进行修改以创建一个新的子类,同时保持父类不变。我们已经在这里编辑了很多内容,因此我将发布一个新的答案,希望没问题。为了它,我会把我以前的答案保留下来
无论如何,我们从您最新的示例(formextends-Tag
)开始
似乎你在试图模仿某种形式,所以请容忍我,让我们用一个简短的例子:
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;
}
}
此外,为了传递$args
依赖项,您必须修改表单构造函数以调用它的父::\u construct($args)
方法
然后运行它
$builder = new TagBuilder();
$builder->setClass('/library/form/form.php', 'Form');
$builder->setArgs(array('wahoo', 'ok'));
$form = $builder->getTag();
这是一个有点长的示例,它意味着更改OP的一些API,但如果我正确理解了这个问题,那么这就是OP希望在其应用程序中模仿的期望行为(或部分行为)
注意:我知道这不是构建器模式的经典示例,对于一些纯粹主义者来说,getTag
方法可能有点模棱两可。好吧,其他人告诉你这是一个糟糕的设计想法。我将提出类似的异议,并告诉您,您可能遇到了一个问题域,其中基于类的OO层次结构无法为您提供您想要的所有好处。如果你对这个想法感到好奇,我建议你阅读史蒂夫·耶格的《通用设计模式》(The Universal Design Pattern)()
但是他有点冗长,所以在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)
您的方法只能是以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
从标签
升级到表单
时,只需更改数组的\u class
键即可。如果需要进行内部状态更改,您可以编写一个函数/方法来处理
你确实失去了为你记录事情的口译员,有些人真的为此而烦恼。大多数人使用Java是因为PHP对他们来说太快太松散了。这是一种动态语言。利用这一事实 我认为这是不可能的,因为PHP不进行分层对象转换(向上/向下转换)。什么是子对象
和父对象
?这样建模有意义吗?通常,您使用继承使某个类或组功能更具体。像鸭子一样,鸟也是动物。你的例子似乎选得不好。在这种情况下,两个对象都应该来自classPerson
,并且都有一个属性parent
。这一点很好。我将添加一些信息,尝试更好地解释它。新:签出“con”
function method($this,$methodName,$args) {
$fullMethodName = "{$this['_class']}_$methodName";
$fullMethodName($this,$args);
}
// and now, the invocation
method($quasiObj,'method1Name',array(6,7));