我有一个类,它返回一个自身的新实例。 这允许我使用一个单独的对象,而不必使用相同的值反复声明新的对象。对于那些想要为什么不扩展课程或其他东西的人来说,它只是让我的生活更轻松,它就像一个魅力,但我的最终目的是将它们全部删除。
例如:
$foo = new myClass('name1','ab','cd');
$bar = $foo->duplicate();
//duplicate() saves the new object in itself in an array:
array_push($this->instance,new myClass('name1','ab','cd'));
//and returns a pointer to the saved instance.
return end($this->instance);
$foo
和$bar
现在共享相同的方法和值,但这些值可以单独修改。
$foo->changeName('newName');
$bar->changeName('newName2');
我的问题是,如果我取消设置创建的第一个类unset($foo)
,PHP会自动取消设置其他实例($bar)
还是垃圾收集器最终会删除它们?
我通过解决$ foo来测试它并在我调用$ foo时给出了一个错误,但是当我调用$ bar时却没有。
我要做的是立即取消设置该类的所有实例。
感谢。
答案 0 :(得分:3)
自动清理?
不,PHP不了解您的架构。它不会删除对象“级联”,它们是独立的实体 - 而且,更多,可以属于不同的范围,例如。简单的代码:
class Test
{
protected $id = null;
protected $uniqid = null;
public function __construct($id)
{
$this->id = $id;//user-passed variable
$this->uniqid = uniqid();//internal: to identify instance
}
public function getCopy()
{
return new self($this->id);
}
public function getIdentity()
{
return $this->uniqid;
}
}
$foo = new Test(3);
$bar = $foo->getCopy();
var_dump($foo->getIdentity());//valid
unset($foo);
//still valid: bar has nothing to do with foo
var_dump($bar->getIdentity());
顺便说一句,对于复制,您可以在PHP中使用clone
(但是,这会导致对象克隆,显然)
简单方法
解决问题的最简单方法是迭代$GLOBALS
,并使用instanceof
进行检查。这有一个严重的缺点:内部函数/方法范围不会受到影响:
//static since doesn't belong to any instance:
public static function cleanup()
{
foreach($GLOBALS as $name=>$var)
{
if($var instanceof self)
{
unset($GLOBALS[$name]);
}
}
}
- 和
$foo = new Test(3);
$bar = $foo->getCopy();
var_dump($foo->getIdentity(), $bar->getIdentity());//valid
Test::cleanup();
//2 x notice:
var_dump($foo, $bar);
注意,这与“子”机制无关(即它将清除全局范围内的所有实例 - 无论从哪个实例复制)。
常见案例
以上示例不执行常见情况下的操作。为什么?想象一下,你将拥有持有人类:
class Holder
{
protected $obj = null;
public function __construct($obj)
{
$this->obj = $obj;
}
public function getData()
{
return $this->obj;
}
}
你会将实例传递给它:
$foo = new Test(3);
$bar = $foo->getCopy();
$baz = new Holder($bar);
- 那么在普通情况下你甚至没有机会处理这种简单的情况。在更复杂的情况下,你也会陷入困境。
怎么做?
我建议:在需要时明确地销毁对象。隐式unset是一个副作用,即使你会以某种方式维护(我可以想象Observer模式+一些全局注册表) - 这将是可怕的副作用,这会破坏你的代码的可读性。关于使用上面我写过的$GLOBALS
的代码也一样 - 我不建议在任何情况下采取这种方式。
答案 1 :(得分:0)
根据我在PHP参考中的理解:
http://www.php.net/manual/en/features.gc.refcounting-basics.php
销毁主实例不会自动销毁所有其他实例,因为它们最终不会指向相同的'zval'。
但是,如果不再引用垃圾收集,垃圾收集最终将销毁所有实例。因为在你的例子中,$ bar仍然引用第二个实例,所以它不会被销毁。
如果你想同时取消所有这些,你可以做什么:
答案 2 :(得分:0)
尝试使用以下代码清除所有php对象。
public function clearAllVars()
{
$vars = get_object_vars($this);
foreach($vars as $key => $val)
{
$this->$key = null;
}
}
}