如何从类中删除PHP对象?

时间:2021-08-08 19:35:07

I know that for some that might sound stupid, but I was thinking if I hava a delete() method in a class that removes all the object data (from DB and file system), how can I destroy/remove the object from within the class.

我知道对于一些可能听起来很愚蠢的人,但我在想如果我在一个删除所有对象数据(来自DB和文件系统)的类中有一个delete()方法,我怎么能从内部销毁/删除对象类。

This is a PHP question. Something like unset($this); Is it possible and wise? And what is the right way to do it?

这是一个PHP问题。像未设置的东西($ this);有可能吗?明智吗?什么是正确的方法呢?

7 个解决方案

#1


6  

Whilst developing on a framework, I came across such issue as well. unset($this) is totally not possible, as $this is just a special pointer that allows you to access the current object's properties and methods.

在开发框架的同时,我也遇到了这样的问题。 unset($ this)完全不可能,因为$ this只是一个特殊的指针,允许您访问当前对象的属性和方法。

The only way is to encapsulate the use of objects in methods / functions so that when the method / function ends, the reference to the object is lost and garbage collector will automatically free the memory for other things.

唯一的方法是在方法/函数中封装对象的使用,这样当方法/函数结束时,对对象的引用就会丢失,垃圾收集器会自动释放内存以用于其他事情。

See example RaiseFile, a class that represents a file:

请参阅示例RaiseFile,一个表示文件的类:

http://code.google.com/p/phpraise/source/browse/trunk/phpraise/core/io/file/RaiseFile.php

http://code.google.com/p/phpraise/source/browse/trunk/phpraise/core/io/file/RaiseFile.php

In the RaiseFile class, it'll be sensible that after you call the delete() method and the file is deleted, the RaiseFile object should also be deleted.

在RaiseFile类中,在调用delete()方法并删除文件之后,还应该删除RaiseFile对象是明智的。

However because of the problem you mentioned, I actually have to insist that RaiseFile points to a file whether or not the file exists or not. Existence of the file can be tracked through the exists() method.

但是,由于您提到的问题,我实际上必须坚持RaiseFile指向文件,无论该文件是否存在。可以通过exists()方法跟踪文件的存在。

Say we have a cut-paste function that uses RaiseFile representation:

假设我们有一个使用RaiseFile表示的剪切粘贴功能:

/**
 * Cut and paste a file from source to destination
 * @param string $file Pathname to source file
 * @param string $dest Pathname to destination file
 * @return RaiseFile The destination file
 */
function cutpaste($file, $dest){
    $f = new RaiseFile($file);
    $d = new RaiseFile($dest);
    $f->copy($d);
    $f->delete();
    return $d;
}

Notice how $f is removed and GC-ed after the function ends because there is no more references to the RaiseFile object $f outside the function.

注意函数结束后如何删除$ f和GC-ed,因为函数外部没有更多对RaiseFile对象$ f的引用。

#2


3  

You cannot unset $this. Or more correctly: unset() on $this only has local effect on the variable. unset() removes the variable from the local scope, which reduces the ref count for the object. If the object is still referenced somewhere else, it will stay in memory and work.

你不能取消这个$。或者更正确:$ set上的unset()只对变量有局部影响。 unset()从本地范围中删除变量,这会减少对象的引用计数。如果对象仍在其他地方引用,它将保留在内存中并工作。

Typically, the value of an ID property is used to determine if an object is stored in the back end. If the ID has a proper value, that object is stored. If the ID is null, it is not stored, yet. On successful storage you then set the ID accordingly. On delete you set the ID property to null again.

通常,ID属性的值用于确定对象是否存储在后端。如果ID具有适当的值,则存储该对象。如果ID为null,则尚未存储。成功存储后,您可以相应地设置ID。在删除时,您再次将ID属性设置为null。

#3


1  

I'm in this same boat now.

我现在在同一条船上。

I'm building a CMS solution from the ground up and have a lot of references between objects; users, groups, categories, forums, topics, posts, etc.

我正在从头开始构建CMS解决方案,并在对象之间有很多引用;用户,群组,类别,论坛,主题,帖子等

I also use an "Object::getObject(id)" loader in each class which ensures there's only one instance of an object per ID, but also means it's even easier for code to pull a reference to existing objects.

我还在每个类中使用“Object :: getObject(id)”加载器,确保每个ID只有一个对象实例,但也意味着代码更容易提取对现有对象的引用。

When the data the object represents gets deleted from the data source, I'd like to wipe the object from memory and nullify all references to it to ensure other code doesn't try to use an obsolete data set.

当对象表示的数据从数据源中删除时,我想从内存中擦除对象并取消对它的所有引用,以确保其他代码不会尝试使用过时的数据集。

Ideally all references should be removed--the referencing code can provide a callback that gets fired at object deletion that can subsequently remove/update the reference. But if the referencing code gets sloppy, I'd rather it error out with a "Not an object" error than actually work with the object.

理想情况下,应删除所有引用 - 引用代码可以提供在删除对象时触发的回调,随后可以删除/更新引用。但是如果引用代码变得草率,我宁愿错误地输出“Not an object”错误而不是实际使用该对象。

Without knowing how to force the destruction from within the object, itself, I'm being forced to:

在不知道如何从对象内部强制破坏的情况下,我*:

  1. Begin almost every non-static method with a check to see if the object has been flagged "deleted", throwing an exception if it is. This ensures any referencing code can't do any harm, but it's a nasty thing to look at in the code.

    开始几乎所有的非静态方法,检查对象是否已被标记为“已删除”,如果是,则抛出异常。这可以确保任何引用代码都不会造成任何伤害,但在代码中查看是件令人讨厌的事情。

  2. Unset every object variable after deletion from the database, so it doesn't linger in memory. Not a big deal but, again: nasty to look at.

    从数据库中删除后取消设置每个对象变量,因此它不会留在内存中。没什么大不了的,但是,再次:讨厌看。

Neither would be needed if I could just destroy the object from within.

如果我可以从内部摧毁物体,那么也不需要。

#4


0  

This depends on how you've structured your class.

这取决于你的课程结构。

If you're following DTO/DAO patterns, your data would be separate from your model and you can simply remove the DTO. If you're not, simply unsetting the data part of the class should do it.

如果您遵循DTO / DAO模式,您的数据将与您的模型分开,您只需删除DTO即可。如果不是,只需取消设置类的数据部分即可。

But in actual terms, I think this is unnecessary since PHP will automatically cleanup at the end of the request. Unless you're working on a giant object that takes up massive amounts of memory, and it's a long process it's not really worth the effort.

但实际上,我认为这是不必要的,因为PHP会在请求结束时自动清理。除非你正在处理一个占用大量内存的巨大物体,而且这是一个漫长的过程,所以不值得努力。

#5


0  

There is a __destruct() magic method which is a destructor for a PHP Class.

有一个__destruct()魔术方法,它是PHP类的析构函数。

Maybe you can put your deletion code in there and as soon as all reference to your objects are deleted, this destructor will be called and the data deleted.

也许您可以将删除代码放在那里,只要删除对所有对象的引用,就会调用此析构函数并删除数据。

#6


0  

Another approach is to make the delete-method static, which then could receive a PDO object and data, that determines what to delete. This way you don't need to initialise the object.

另一种方法是使delete-method静态,然后可以接收PDO对象和数据,确定要删除的内容。这样您就不需要初始化对象了。

#7


0  

Here is a sample solution which would be "reasonably usable" when implemented in well defined relationship/reference patterns, usually I drop something like this in my composites. To actually use the current code as I've done in this example in a real life would be going through too much trouble but it's just to illustrate the how-to-point.

这是一个示例解决方案,当在明确定义的关系/参考模式中实现时,它将是“合理可用的”,通常我会在我的复合材料中删除这样的东西。实际使用当前代码,就像我在现实生活中所做的那样,会遇到太多麻烦,但这只是为了说明如何进行操作。

An object can't just magically disappear - it will only be deleted (garbage collected) once there is nothing pointing at it. So "all" an object has to do is to keep track of everything that refers to it. It is fairly low friction when you have all the reference management built in - objects are created and passed on only by fixed methods.

一个对象不能只是神奇地消失 - 一旦没有任何指向它,它将只被删除(垃圾收集)。所以一个对象必须要做的就是跟踪引用它的所有内容。当你内置了所有的引用管理时,它的摩擦力相当低 - 只能通过固定方法创建和传递对象。

Lets begin with a simple interface so we would be able to tell if it is safe to pass our reference to an object or not.

让我们从一个简单的接口开始,这样我们就可以判断是否可以安全地传递对象的引用。

interface removableChildInterface
{

    public function removeChild($obj);

}

A class which can safely hold a reference to our object.

一个可以安全地保存对象的引用的类。

class MyParent implements removableChildInterface
{

    public $children = array();

    public function removeChild($child)
    {
        $key = array_search($child, $this->children);
        unset($this->children[$key]);
    }

}

And finally a class with the ability to self-destruct aka trigger the process of being removed by all of its parents.

最后,一个具有自毁能力的类也会触发被其所有父母移除的过程。

class Suicidal
{

    private $parents = array(); // Store all the reference holders
    private $id; // For example only
    private $memory = ''; // For example only
    public static $counter = 0; // For example only

    public function __construct(&$parent)
    {
        // Store a parent on creation
        $this->getReference($parent);
        // For the example lets assing an id
        $this->id = 'id_' . ++self::$counter;
        // and generate some weight for the object.
        for ($i = 0; $i < 100000; $i++) {
            $this->memory .= md5(mt_rand() . $i . self::$counter);
        }
    }

    // A method to use for passing the object around after its creation.
    public function getReference(&$parent)
    {
        if (!in_array($parent, $this->parents)) {
            $this->parents[] = &$parent;
        }
        return $this;
    }

    // Calling this method will start the removal of references to this object.
    // And yes - I am not actually going to call this method from within this
    // object in the example but the end result is the same.
    public function selfDestruct()
    {
        foreach ($this->parents as &$parent) {
            if (is_array($parent)) {
                $key = array_search($this, $parent);
                unset($parent[$key]);
                echo 'removing ' . $this->id . ' from an array<br>';
            } elseif ($parent instanceof removableChildInterface) {
                $parent->removeChild($this);
                echo 'removing ' . $this->id . ' from an object<br>';
            }
            // else throw your favourite exception
        }
    }

    // A final shout out right before being garbage collected.
    public function __destruct()
    {
        echo 'destroying ' . $this->id . '<br>';
    }

}

And for the example of usage, holding the reference in an array, in an object implementing our interface and the $GLOBALS array.

对于使用示例,将引用保存在数组中,在实现我们的接口的对象和$ GLOBALS数组中。

// Define collectors
$array = array();
$parent = new MyParent();

// Store objects directly in array
$array['c1'] = new Suicidal($array);
$array['c2'] = new Suicidal($array);

// Make a global reference and store in object
$global_refrence = $array['c1']->getReference($GLOBALS);
$parent->children[] = $array['c1']->getReference($parent);

// Display some numbers and blow up an object.
echo 'memory usage with 2 items ' . memory_get_usage() . ' bytes<br>';
$array['c1']->selfDestruct();
echo 'memory usage with 1 item ' . memory_get_usage() . ' bytes<br>';

// Second object is GC-d the natural way after this line
echo '---- before eof ----' . '<br>';

Output:

输出:

memory usage with 2 items 6620672 bytes
removing id_1 from an array
removing id_1 from an array
removing id_1 from an object
destroying id_1
memory usage with 1 item 3419832 bytes
---- before eof ----
destroying id_2

#1


6  

Whilst developing on a framework, I came across such issue as well. unset($this) is totally not possible, as $this is just a special pointer that allows you to access the current object's properties and methods.

在开发框架的同时,我也遇到了这样的问题。 unset($ this)完全不可能,因为$ this只是一个特殊的指针,允许您访问当前对象的属性和方法。

The only way is to encapsulate the use of objects in methods / functions so that when the method / function ends, the reference to the object is lost and garbage collector will automatically free the memory for other things.

唯一的方法是在方法/函数中封装对象的使用,这样当方法/函数结束时,对对象的引用就会丢失,垃圾收集器会自动释放内存以用于其他事情。

See example RaiseFile, a class that represents a file:

请参阅示例RaiseFile,一个表示文件的类:

http://code.google.com/p/phpraise/source/browse/trunk/phpraise/core/io/file/RaiseFile.php

http://code.google.com/p/phpraise/source/browse/trunk/phpraise/core/io/file/RaiseFile.php

In the RaiseFile class, it'll be sensible that after you call the delete() method and the file is deleted, the RaiseFile object should also be deleted.

在RaiseFile类中,在调用delete()方法并删除文件之后,还应该删除RaiseFile对象是明智的。

However because of the problem you mentioned, I actually have to insist that RaiseFile points to a file whether or not the file exists or not. Existence of the file can be tracked through the exists() method.

但是,由于您提到的问题,我实际上必须坚持RaiseFile指向文件,无论该文件是否存在。可以通过exists()方法跟踪文件的存在。

Say we have a cut-paste function that uses RaiseFile representation:

假设我们有一个使用RaiseFile表示的剪切粘贴功能:

/**
 * Cut and paste a file from source to destination
 * @param string $file Pathname to source file
 * @param string $dest Pathname to destination file
 * @return RaiseFile The destination file
 */
function cutpaste($file, $dest){
    $f = new RaiseFile($file);
    $d = new RaiseFile($dest);
    $f->copy($d);
    $f->delete();
    return $d;
}

Notice how $f is removed and GC-ed after the function ends because there is no more references to the RaiseFile object $f outside the function.

注意函数结束后如何删除$ f和GC-ed,因为函数外部没有更多对RaiseFile对象$ f的引用。

#2


3  

You cannot unset $this. Or more correctly: unset() on $this only has local effect on the variable. unset() removes the variable from the local scope, which reduces the ref count for the object. If the object is still referenced somewhere else, it will stay in memory and work.

你不能取消这个$。或者更正确:$ set上的unset()只对变量有局部影响。 unset()从本地范围中删除变量,这会减少对象的引用计数。如果对象仍在其他地方引用,它将保留在内存中并工作。

Typically, the value of an ID property is used to determine if an object is stored in the back end. If the ID has a proper value, that object is stored. If the ID is null, it is not stored, yet. On successful storage you then set the ID accordingly. On delete you set the ID property to null again.

通常,ID属性的值用于确定对象是否存储在后端。如果ID具有适当的值,则存储该对象。如果ID为null,则尚未存储。成功存储后,您可以相应地设置ID。在删除时,您再次将ID属性设置为null。

#3


1  

I'm in this same boat now.

我现在在同一条船上。

I'm building a CMS solution from the ground up and have a lot of references between objects; users, groups, categories, forums, topics, posts, etc.

我正在从头开始构建CMS解决方案,并在对象之间有很多引用;用户,群组,类别,论坛,主题,帖子等

I also use an "Object::getObject(id)" loader in each class which ensures there's only one instance of an object per ID, but also means it's even easier for code to pull a reference to existing objects.

我还在每个类中使用“Object :: getObject(id)”加载器,确保每个ID只有一个对象实例,但也意味着代码更容易提取对现有对象的引用。

When the data the object represents gets deleted from the data source, I'd like to wipe the object from memory and nullify all references to it to ensure other code doesn't try to use an obsolete data set.

当对象表示的数据从数据源中删除时,我想从内存中擦除对象并取消对它的所有引用,以确保其他代码不会尝试使用过时的数据集。

Ideally all references should be removed--the referencing code can provide a callback that gets fired at object deletion that can subsequently remove/update the reference. But if the referencing code gets sloppy, I'd rather it error out with a "Not an object" error than actually work with the object.

理想情况下,应删除所有引用 - 引用代码可以提供在删除对象时触发的回调,随后可以删除/更新引用。但是如果引用代码变得草率,我宁愿错误地输出“Not an object”错误而不是实际使用该对象。

Without knowing how to force the destruction from within the object, itself, I'm being forced to:

在不知道如何从对象内部强制破坏的情况下,我*:

  1. Begin almost every non-static method with a check to see if the object has been flagged "deleted", throwing an exception if it is. This ensures any referencing code can't do any harm, but it's a nasty thing to look at in the code.

    开始几乎所有的非静态方法,检查对象是否已被标记为“已删除”,如果是,则抛出异常。这可以确保任何引用代码都不会造成任何伤害,但在代码中查看是件令人讨厌的事情。

  2. Unset every object variable after deletion from the database, so it doesn't linger in memory. Not a big deal but, again: nasty to look at.

    从数据库中删除后取消设置每个对象变量,因此它不会留在内存中。没什么大不了的,但是,再次:讨厌看。

Neither would be needed if I could just destroy the object from within.

如果我可以从内部摧毁物体,那么也不需要。

#4


0  

This depends on how you've structured your class.

这取决于你的课程结构。

If you're following DTO/DAO patterns, your data would be separate from your model and you can simply remove the DTO. If you're not, simply unsetting the data part of the class should do it.

如果您遵循DTO / DAO模式,您的数据将与您的模型分开,您只需删除DTO即可。如果不是,只需取消设置类的数据部分即可。

But in actual terms, I think this is unnecessary since PHP will automatically cleanup at the end of the request. Unless you're working on a giant object that takes up massive amounts of memory, and it's a long process it's not really worth the effort.

但实际上,我认为这是不必要的,因为PHP会在请求结束时自动清理。除非你正在处理一个占用大量内存的巨大物体,而且这是一个漫长的过程,所以不值得努力。

#5


0  

There is a __destruct() magic method which is a destructor for a PHP Class.

有一个__destruct()魔术方法,它是PHP类的析构函数。

Maybe you can put your deletion code in there and as soon as all reference to your objects are deleted, this destructor will be called and the data deleted.

也许您可以将删除代码放在那里,只要删除对所有对象的引用,就会调用此析构函数并删除数据。

#6


0  

Another approach is to make the delete-method static, which then could receive a PDO object and data, that determines what to delete. This way you don't need to initialise the object.

另一种方法是使delete-method静态,然后可以接收PDO对象和数据,确定要删除的内容。这样您就不需要初始化对象了。

#7


0  

Here is a sample solution which would be "reasonably usable" when implemented in well defined relationship/reference patterns, usually I drop something like this in my composites. To actually use the current code as I've done in this example in a real life would be going through too much trouble but it's just to illustrate the how-to-point.

这是一个示例解决方案,当在明确定义的关系/参考模式中实现时,它将是“合理可用的”,通常我会在我的复合材料中删除这样的东西。实际使用当前代码,就像我在现实生活中所做的那样,会遇到太多麻烦,但这只是为了说明如何进行操作。

An object can't just magically disappear - it will only be deleted (garbage collected) once there is nothing pointing at it. So "all" an object has to do is to keep track of everything that refers to it. It is fairly low friction when you have all the reference management built in - objects are created and passed on only by fixed methods.

一个对象不能只是神奇地消失 - 一旦没有任何指向它,它将只被删除(垃圾收集)。所以一个对象必须要做的就是跟踪引用它的所有内容。当你内置了所有的引用管理时,它的摩擦力相当低 - 只能通过固定方法创建和传递对象。

Lets begin with a simple interface so we would be able to tell if it is safe to pass our reference to an object or not.

让我们从一个简单的接口开始,这样我们就可以判断是否可以安全地传递对象的引用。

interface removableChildInterface
{

    public function removeChild($obj);

}

A class which can safely hold a reference to our object.

一个可以安全地保存对象的引用的类。

class MyParent implements removableChildInterface
{

    public $children = array();

    public function removeChild($child)
    {
        $key = array_search($child, $this->children);
        unset($this->children[$key]);
    }

}

And finally a class with the ability to self-destruct aka trigger the process of being removed by all of its parents.

最后,一个具有自毁能力的类也会触发被其所有父母移除的过程。

class Suicidal
{

    private $parents = array(); // Store all the reference holders
    private $id; // For example only
    private $memory = ''; // For example only
    public static $counter = 0; // For example only

    public function __construct(&$parent)
    {
        // Store a parent on creation
        $this->getReference($parent);
        // For the example lets assing an id
        $this->id = 'id_' . ++self::$counter;
        // and generate some weight for the object.
        for ($i = 0; $i < 100000; $i++) {
            $this->memory .= md5(mt_rand() . $i . self::$counter);
        }
    }

    // A method to use for passing the object around after its creation.
    public function getReference(&$parent)
    {
        if (!in_array($parent, $this->parents)) {
            $this->parents[] = &$parent;
        }
        return $this;
    }

    // Calling this method will start the removal of references to this object.
    // And yes - I am not actually going to call this method from within this
    // object in the example but the end result is the same.
    public function selfDestruct()
    {
        foreach ($this->parents as &$parent) {
            if (is_array($parent)) {
                $key = array_search($this, $parent);
                unset($parent[$key]);
                echo 'removing ' . $this->id . ' from an array<br>';
            } elseif ($parent instanceof removableChildInterface) {
                $parent->removeChild($this);
                echo 'removing ' . $this->id . ' from an object<br>';
            }
            // else throw your favourite exception
        }
    }

    // A final shout out right before being garbage collected.
    public function __destruct()
    {
        echo 'destroying ' . $this->id . '<br>';
    }

}

And for the example of usage, holding the reference in an array, in an object implementing our interface and the $GLOBALS array.

对于使用示例,将引用保存在数组中,在实现我们的接口的对象和$ GLOBALS数组中。

// Define collectors
$array = array();
$parent = new MyParent();

// Store objects directly in array
$array['c1'] = new Suicidal($array);
$array['c2'] = new Suicidal($array);

// Make a global reference and store in object
$global_refrence = $array['c1']->getReference($GLOBALS);
$parent->children[] = $array['c1']->getReference($parent);

// Display some numbers and blow up an object.
echo 'memory usage with 2 items ' . memory_get_usage() . ' bytes<br>';
$array['c1']->selfDestruct();
echo 'memory usage with 1 item ' . memory_get_usage() . ' bytes<br>';

// Second object is GC-d the natural way after this line
echo '---- before eof ----' . '<br>';

Output:

输出:

memory usage with 2 items 6620672 bytes
removing id_1 from an array
removing id_1 from an array
removing id_1 from an object
destroying id_1
memory usage with 1 item 3419832 bytes
---- before eof ----
destroying id_2