使用同一类的另一个对象初始化PHP类的实例(以及任何优点和缺点)(理想情况下,在PHP 4.x中)
这里initialize()
基本上是我希望能够做到的(例子从我的用例中非常简化,见下文):
$product = new Product('Widget');
$product2 = new Product('Widget #2');
$product->initialize($product2);
echo $product->name; // echos "Widget #2"
class Product {
var $name;
function __constructor($name) {
$this->name = $name;
}
function initialize($product) {
// I know this cannot be done this way in PHP.
// What are the alternatives and their pros & cons?
$this = $product;
}
}
我知道这可能不是“良好的编程习惯”;我有20多年的其他语言编程经验,我知道什么是好的,什么不是。所以,如果这样做有意义,我们希望我们不会被挂断。我有一个用例使用一些我无法改变的开源代码,所以请耐心等待我的需要。我实际上是在围绕一些埋在WordPress核心深处的非常丑陋的数组代码创建一个OOP包装器。
我正在尝试编写它,所以在未来的版本中,他们可以摆脱丑陋的基于数组的代码,因为每个人都将使用新的API,否则完全封装这些讨厌的数组。但为了使它优雅地工作,我需要能够执行上述操作(在PHP 4.x中)并且我不想编写仅复制属性的代码。
提前感谢您的帮助。
你们许多人都在暗示clone
,但除非我误解了这个问题。 clone
制作副本;这不是问题的症结所在。 我试图让构造的对象“成为”传入的对象。此时我假设没有办法做到这一点事实上,5个答案中有0个提出了建议,但我会等一段时间再选择最好的,以防我的问题不明确。
答案 0 :(得分:5)
在PHP 5中,对象克隆可能更相关:
http://php.net/manual/en/language.oop5.cloning.php
您可以定义一种特殊的__clone
方法。
在PHP 4和5中,您可以通过以下方式复制属性:
function copy($obj)
{
foreach (get_object_vars($obj) as $key => $val)
{
$this->$key = $val;
}
}
但是,您写道“我不想编写仅复制属性的代码”,而且我不确定您的意思。
答案 1 :(得分:2)
这样做的首选方法是使用clone
关键字,并根据需要实施适当的__clone()
方法,如其他海报所述。另一种做法的方法(con:慢,专业:可以存储,通过网络发送,在php4 / 5中工作相同)是序列化一个对象,然后反序列化以创建具有相同变量值的新副本。
示例:
$productCopy = unserialize(serialize($product));
编辑:对不起,误解了你的要求。您必须使用构造函数中传入的对象变量初始化正在构造的对象的变量。您不能从构造函数返回对另一个对象的引用。
示例:
public function __construct($name, $object = null) {
if($object) {
foreach(get_object_vars($object) as $k => $v) {
$this->$k = $v;
}
} else {
$this->name = $name;
}
}
答案 2 :(得分:1)
class Product {
var $name;
function __construct($value) {
if (is_a($value, 'Product')) {
$this->name = $value->name;
} else {
$this->name = $value;
}
}
}
同样,如果您愿意,可以使用instanceof
代替is_a
(取决于您的PHP版本)。
现在您可以将Product实例或名称传递给构造。
$product = new Product('Something');
$clone = new Product($product);
答案 3 :(得分:1)
到目前为止,这是最好的方法:
http://www.blrf.net/howto/51_PHP__How_to_control_object_instances_in_PHP_.html
不要使用“new”,而是使用返回所需实例的静态函数。
我做了以下事情:
class MyClass {
private static $_instances;
public static function get($id) {
if (!self::$_instances) self::$_instances = Array();
$class = get_called_class();
if (!array_key_exists($class, self::$_instances)) self::$_instances[$class] = Array();
if (!is_numeric($id) || $id == '') throw new Exception('Cannot instantiate a non-numeric ID.');
if (array_key_exists($id, self::$_instances[$class])) return self::$_instances[$class][$id];
else {
self::$_instances[$class][$id] = new static($id);
return self::$_instances[$class][$id];
}
}
function __construct($id=false) {
// new instance code...
// I use $id=false to create new a db table row not load an old one
}
}
用法:
// New instance
$a = new MyClass();
$a = new MyClass;
// MyClass with $id = 1
$b = MyClass::get(1);
$c = MyClass::get(1);
$d = new MyClass(1);
$b and $c point to the same object, while $d is a new one.
注意事项:
垃圾收集将不再适用,因为您的实例存储在静态数组中
您必须更改代码才能使用MyClass :: get
我的代码中的注释:
使用“new static”而不是“new self”调用新实例以使用后期静态绑定。
您可以将构造函数设置为private。如果您使用“new”,这将破坏所有旧代码,但会确保您不会获得双重实例或更多。你必须在get函数的参数和代码中改变一点,以允许$ id = false或$ id = -1或其他。
答案 4 :(得分:0)
也许
$product = new Product('Widget');
$product2 = new Product(null, $product);
echo $product2->name; // echos "Widget #2"
class Product {
var $name;
function __constructor($name, $product = null) {
$this->name = !empty($name) ? $name : $product->name;
}
}
答案 5 :(得分:0)
添加另一个答案,因为它完全不同。
$product = new Product('Widget');
$product2 = new Product('Widget #2');
$product =& $product2;
echo $product->name; // echos "Widget #2"
这应该有效。