取消设置对象 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:未将对象引用设置为对象的实例

PHP 服务器在未将对象引用设置为对象实例时出现 C# Soap 客户端错误

php面向对象2

PHP无法取消设置对象内的数组元素

.NET 4.5.1 跟踪所有取消任务?

如何跟踪同一用户(对象)的多个实例