Prevent destructor from being called manually

2019-09-02 02:39发布

问题:

I have this class:

class Test
{
    private $test = 'ok';

    public function doTest()
    {
        echo $this->test;
    }

    public function __destruct()
    {
        $this->test = 'not ok';
    }
}

and the following test case:

$test = new Test;
$test->__destruct(); // I wish this would throw a Fatal Error or something...
$test->doTest(); // prints "not ok"

What I want to accomplish is to prevent __destruct() from being called manually, so that doTest() will never print "not ok".

I tried setting the destructor's visibility to private, but that just leads to a Fatal Error on object destruction. An option would be to set a flag $this->destructed in the destructor and then throw an Exception in doTest() if this flag is true, but it wouldn't be very efficient to check for this flag every time the method is called.

So, a private destructor is not possible and a flag $this->destructed is ugly. Are there better ways?

回答1:

If you don't want the destructor to be called, don't implement it. Instead, use a private delegate to do the shutdown stuff.

Your class:

class Test
{
    private $delegate;

    public function __construct()
    {
        $this->delegate = new TestDelegate;
    }

    public function doTest()
    {
        echo $this->delegate->test."\n";
    }
}

Delegate:

class TestDelegate
{
    public $test = 'ok';

    public function __destruct()
    {
        $this->test = 'not ok';
        echo __METHOD__." called\n";
    }
}

Test:

$test = new Test;
//$test->__destruct(); // fatal error
$test->doTest(); // prints "ok"
// TestDelegate::__destruct() gets called automatically

Now, this may introduce other problems. How to make sure the delegate gets registered if a child class implements a constructor and forgets to call its parent constructor? And wouldn't it break things if the constructor gets called multiple times?

To deal with that, make the constructor final and private and use a factory method:

public static function create()
{
    return new static;
}