【问题标题】:(PHP) Unset an object from within the class code(PHP) 从类代码中取消设置对象
【发布时间】:2012-02-13 20:47:17
【问题描述】:

是否可以通过执行特定类的代码来取消设置(清理或取消实例化)该类的对象?

我的场景是,由于某种原因,我达到了该对象不再存在的意义,所以我想通过杀死它在内存中的引用来确保它不会再次被使用。

这是一个 sn-p 示例:

class Foo {
    public $bar = "doh!";
    function destroy() {
        // ???    
    }
}
$o = new Foo();
echo $o->bar . '\n';
$o->destroy();
echo $o->bar . '\n'; // I expect an error here...

如果我在类代码之外执行“取消设置”命令,它显然有效:

$o = new Foo();
unset($o);
echo $o->bar . '\n'; // PHP Notice:  Undefined property: Foo::$bar in ...

但我尝试在“destroy”方法中通过调用“unset”或创建自定义“__destruct”来执行此操作,但均未奏效。

非常欢迎任何想法。

干杯,

【问题讨论】:

  • 你取消了什么,你能写出确切的行吗..
  • php - unset $this的可能重复

标签: php oop


【解决方案1】:

考虑到您不能明确销毁对象

允许 PHP 垃圾收集器作用于对象的方法是:

$var = null; // set to null
unset($var); // unset

对象将停留在那里。但是,如果您取消设置对象并且您的脚本将 PHP 推到内存限制,则不需要的对象将被垃圾收集。我会选择 unset() ,因为它有更好的性能 (not tested but documented on one of the comments from the PHP official manual)。

也就是说,请记住 PHP 总是会在页面被提供后立即销毁对象。因此,只有在非常长的循环和/或大量密集页面上才需要这样做。

【讨论】:

  • 使用unset永远不会带来更好的性能。不调用函数总是比调用它更快
  • @zerkms 除非您的脚本占用大量内存,否则有时需要在执行期间进行清理。在那种特定情况下......应该使用 unset 。但是,如果您不需要它,则不应使用它,因为它不会加快速度。
  • “除非您的脚本占用大量内存,否则在某些时候需要在执行期间进行清理”——这一切都与否则脚本根本无法工作有关的事实有关。使用unset 释放一些内存!= 使用unset 使脚本更快。
  • @zerkms 同意了。但我很困惑,OP是指速度吗?在我的问题上,我确实说“这只能用于……等”。
  • 性能不仅与速度有关,还与计算机资源消耗有关;)
【解决方案2】:

unset($o) 有什么问题?如果它真的冒犯了您,您可以将该行为包装在静态类方法中:

class Foo {
    public static function destroy(&$foo) {
        unset($foo);
    }
}
Foo::destroy($o);

【讨论】:

  • 这行不通。 unset 在这种情况下只是删除一个引用,而不是对象本身。但可能$foo = null; 会做这项工作
  • 这个想法是在特定情况下对象应该不再存在,但这个决定是由类本身的代码做出的......所以关键是你做不知道你应该从实例化对象的角度杀死对象。
【解决方案3】:

从 php 5.2 开始,可以使用spl_object_hash,但不应该使用它...

class MyClass {
    public function destroy(){
        foreach($GLOBALS as $k => $v){
            // bucabay is totally right ! It's faster this way
            //if(is_object($v) && (spl_object_hash($v) == spl_object_hash($this))){
            if($v === $this){
                    $GLOBALS[$k] = null;
                    return;
            }
        }
    }
}
$a = new MyClass;
$b = new MyClass;

var_dump($a, $b); // class MyClass#1 (0) {}class MyClass#2 (0) {}
echo "\n";

$a->destroy();
var_dump($a, $b); // NULL class MyClass#2 (0) {}
echo "\n";

$b->destroy();
var_dump($a, $b); // NULL NULL

【讨论】:

  • 您只需与 PHP 5.2 之前的 === 进行比较。 ($v === $this)
【解决方案4】:

这是不可能的。您可以取消设置变量或将其设置为 null,但不能保证您不会对该对象有任何引用($b = $o; $b 不会被 unset($o); 破坏)。

一个丑陋的解决方案是在你的类中添加一个字段,例如destroyed,检查每个方法是否不正确,如果是则抛出异常。

【讨论】:

    【解决方案5】:

    是的,似乎不可能实现......另一种肮脏的方式可能是:

    class Foo {
        public $bar = "doh!";
        function destroy() {
            unset($this->bar); // and do this for EVERY property of this class
        }
    }
    $o = new Foo();
    echo $o->bar . '\n';
    $o->destroy();
    echo $o->bar . '\n'; // PHP Notice:  Undefined property: Foo::$bar in...
    

    但是,对象仍然存在,方法仍然可以访问。

    【讨论】:

      【解决方案6】:

      你可以使用:

      public function delete()
          {
              foreach($GLOBALS as $name => $value) {
                  if ($GLOBALS[$name] === $this) {
                      unset($GLOBALS[$name]);
                  }
              }
          }
      

      任何 PHP 版本。这仅在对象位于全局范围内时才有效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-13
        • 2013-03-04
        • 2014-01-29
        • 1970-01-01
        • 2015-09-11
        • 1970-01-01
        • 2017-05-05
        相关资源
        最近更新 更多