取消设置对象 PHP 的所有实例
Posted
技术标签:
【中文标题】取消设置对象 PHP 的所有实例【英文标题】:Unset all instances of an object PHP 【发布时间】:2014-01-29 01:54:53 【问题描述】:我有一个类,它有一个返回自身新实例的方法。 这允许我使用一个对象,而不必一遍又一遍地声明具有相同值的新对象。对于那些想知道为什么不扩展课程或其他东西的人,它只是让我的生活更轻松,它就像一种魅力,但我的最终目的是将它们全部删除。
例如:
$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 时却没有。
我要做的是一次取消设置该类的所有实例。
谢谢。
【问题讨论】:
如果您想确定性地销毁对象的“集合”,请将它们保存在某种真正的集合中,然后unset
一次将它们全部(循环)。
【参考方案1】:
根据我对 PHP 参考的理解:
http://www.php.net/manual/en/features.gc.refcounting-basics.php
销毁主实例不会自动销毁所有其他实例,因为它们最终不会指向同一个“zval”。
但是,如果不再引用它们,垃圾收集最终会销毁所有实例。由于在您的示例中 $bar 仍然引用第二个实例,因此它不会被销毁。
如果你想同时取消所有设置,你可以做什么:
-
使用引用对象的所有实例的静态数组
每次创建新对象时,在类的静态数组中添加对该对象的引用
使用静态函数 unsetAll() 循环遍历此数组并一一取消设置所有实例
【讨论】:
我忘了说所有实例都保存在主对象中,并返回一个指向保存实例的指针。 我不确定,正如我之前提到的,在取消主对象后调用新实例时它不会给我一个错误。看看我的问题,我添加了更具体的代码示例。谢谢! 我的解释能力不好,很差,为了更清楚而编辑了答案【参考方案2】:尝试以下代码清除所有 php 对象。
public function clearAllVars()
$vars = get_object_vars($this);
foreach($vars as $key => $val)
$this->$key = null;
【讨论】:
【参考方案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);
-那么在普通情况下,即使是这种简单的情况,您也没有机会处理。而对于更复杂的情况,你也会陷入困境。
怎么办?
我建议:在需要时明确销毁对象。隐式取消设置是一种副作用,即使你会以某种方式维护它(我可以想象观察者模式 + 一些全局注册表) - 这将是可怕的副作用,这会破坏你的代码的可读性。代码也是如此,使用我上面写的$GLOBALS
- 我不建议在任何情况下这样做。
【讨论】:
非常感谢,这看起来非常有用且解释清楚,快速的问题,只是因为我想保留我到目前为止所做的事情,如果不是我明白这是不可能的:如果我返回一个传递引用或指针? &$this->实例?显然,如果这有效 Holder($bar) 将返回一个错误,但我们的想法是要小心并知道我们在做什么。谢谢! 它仍然不可靠,因为您无法确定类/函数内部发生了什么。可能是以某种方式复制数据? (例如,通过clone
)。在通常情况下,您会失去跟踪 - 这是肯定的以上是关于取消设置对象 PHP 的所有实例的主要内容,如果未能解决你的问题,请参考以下文章
NODEJS / PHP WSDL SOAP:未将对象引用设置为对象的实例