如果我有一个扩展类 Bar 的类 Foo 和一个 Bar 的实例,那么无论如何是否可以使用该 Bar 的实例来“填充”一个新的 Foo 实例?
本质上,我只能检索 Bar,但我想在我的代码中使用 Foo,因为它给了我很多额外的方法。
我看到很多解决方案都提出了类似的问题,但它们似乎都是 python 或 c#。
我无法使用 ReflectionClass::newInstanceArgs,因为我无法访问进入 Bar 构造函数的数据以首先创建它。
如果我有一个扩展类 Bar 的类 Foo 和一个 Bar 的实例,那么无论如何是否可以使用该 Bar 的实例来“填充”一个新的 Foo 实例?
本质上,我只能检索 Bar,但我想在我的代码中使用 Foo,因为它给了我很多额外的方法。
我看到很多解决方案都提出了类似的问题,但它们似乎都是 python 或 c#。
我无法使用 ReflectionClass::newInstanceArgs,因为我无法访问进入 Bar 构造函数的数据以首先创建它。
推荐的方法是通过依赖注入。您的构造函数 forFoo
可以接受 的实例Bar
,然后您必须编写代码以Foo
从对象加载新对象的状态Bar
。
如果 PHP 具有完全符合您描述的功能,那将是有问题的,因为即使Foo
extends Bar
,这两个类仍然可能非常不同。我不明白 PHP 是如何聪明到知道如何自动将一个类的实例转换为另一个类的实例。
话虽如此,在正确的情况下,下面的(非常hacky)“解决方案”可以做你描述的事情。我不建议实际使用它。我主要只是想表明你必须诉诸一些奇怪的东西才能做到这一点。
function convertObject($object, $newClass)
{
return unserialize(
preg_replace(
'/^O\:\d+\:"[^"]+"/',
'O:'.strlen($newClass).':"'.$newClass.'"',
serialize($object)
)
);
}
没有内置的方法可以轻松地做你想做的事。这些类的接口必须重新设计一点。也许是这样的:
<?php
class Bar
{
...
}
class Foo extends Bar
{
public static function fromBar(Bar $bar)
{
$foo = new self();
... (copy data here) ...
return $foo;
}
}
我刚刚写了一些此示例基于扩展自定义驱动程序的内容,这些驱动程序可能需要为上述核心驱动程序文件提供额外的支持包。
// File: parent.php
class parent_class() {
protected $_protected_object; // set in constructor
protected $_protected_var = "Something dynamic";
public function __construct() {
// keep in mind that if you don't override this constructor, this will execute when extended
}
public function create_resource() {
$this->_protected_object = new SomeObjectInstance();
}
public function child_class() {
static $child = null;
if (is_null($child)) {
$file = "child.php";
if (!\file_exists($file)) {
throw new Exception("Couldn't load '$file', doesn't exist");
} else {
require_once($file);
$child = new child_class();
$child->__overload("_protected_object", $this->_protected_object)->__overload("_protected_var", $this->_protected_var);
}
}
return $child;
}
}
// File: child.php
class child_class extends parent_class {
protected function __overload($index, &$value) {
$this->$index =& $value;
return $this;
}
public function __construct() {
// REMEMBER: if you don't declare this method, the parent's constructor will execute
}
public function extended_func() {
// code
}
public function etc() {
// code
}
}
// Code instantiating objects:
$parent = new parent_class();
$parent->create_resource();
var_dump($parent);
/**
* Would output something like this:
*
* object(parent_class)#1 (2) {
* ["_protected_object":protected]=>
* object(SomeObjectInstance)#2 (*) {
* %OBJECT PROPERTIES%
* }
* ["_protected_var":protected]=>
* string(17) "Something dynamic"
* }
*/
$child = $parent->child_class();
var_dump($child);
/**
* Would output something like this:
*
* object(child_class)#3 (2) {
* ["_protected_object":protected]=>
* &object(SomeObjectInstance)#2 (*) {
* %OBJECT PROPERTIES%
* }
* ["_protected_var":protected]=>
* &string(17) "Something dynamic"
* }
*/
请注意,$child 的第二个 var_dump() 输出与 $parent 相同的信息,只是您现在可以看到所述属性前面带有与号 (&),表示现在有引用。因此,如果您更改父类实例中关于这两个属性的任何内容,它将反映在子类实例中。