Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP5, Exception in destructor

I am now reading book "PHP5 for professionals", it's a 2006 year publication. And in one example they throw exception in destructor, long time I couldn't understood why my last exception in destructor didn't work, then I searched about it and found that in PHP => 5.3 it's not available to throw exception in destructor. So how it's better to do, if in destructor I update my database if variable $needsUpdate = true; and close my database connection, so I wanted to throw exception if database couldn't be updated. For example exception I throw in my DB class, but catch they in main file, like this:

Its class Widget:

class Widget {

    private $_id;
    private $_name;
    private $_description; private $_hDB;
    private $_needsUpdating = false;

    public function __construct($widgetID) {

        $this->_hDB = new mysqli('localhost', 'phpbook', 'Un+)J=<AaH', 'phpbook');
        if (! $this->_hDB) {
            throw new Exception('Не удалось подключится к базе данных');
        }
        $sql = "SELECT `name`, `description` FROM widgets WHERE id = '$widgetID'";
        $rs = $this->_hDB->query($sql);

        if (! $rs) {
            throw new Exception("Произошла ошибка при выборе базы данных");
        }

        if (! $rs->num_rows) {
            throw new Exception("Указаная запись в базе данных отсутствует");
        }
        $data = $rs->fetch_assoc();
        $this->_id = $widgetID;
        $this->_name = $data['name'];
        $this->_description = $data['description'];

    }

    public function getName() {
        return $this->_name;
    }

    public function getDescription() {
        return $this->_description;
    }

    public function setName($name) {
        $this->_name = $name;
        $this->_needsUpdating = true;
    }

    public function setDescription($description) {
        $this->_description = $description;
        $this->_needsUpdating = true;
    }

    public function __destruct() {
        if (! $this->_needsUpdating) {
            return;
        }

        $sql = 'UPDAT2E `widgets` SET';
        $sql .= ' `name` = "' . $this->_hDB->real_escape_string($this->_name) . '",';
        $sql .= ' `description` = "' . $this->_hDB->real_escape_string($this->_description) . '" ';
        $sql .= 'WHERE id = ' . $this->_id;


        $rs = $this->_hDB->query($sql);
        if (! $rs) {
            throw new Exception("Произошла ошибка при обновлении базы данных");
        }
        $this->_hDB->close();
    }
}

And this is the main file.

try {
    $widget = new Widget(2);
    echo "Name: " . $widget->getName() . "<br />\n";
    echo "Description: " . $widget->getDescription() . "<br />\n";
    $widget->setName("Iphone 4 / 64GB");
    $widget->setDescription("New Phone, black color, blablabla");

} catch (Exception $e) {
    die("An error has occurred: " . $e->getMessage());
}

And last exception in __destruct() didn't work.

So is there a nice way to throw exception if update database failed? Or is there other correct way, and I didn't understand something?

like image 457
kxc Avatar asked Oct 21 '22 17:10

kxc


1 Answers

Exceptions in the destructor (can) lead to fatal errors. The documentation states this here: construct">http://us.php.net/_construct

Note: Attempting to throw an exception from a destructor (called in the time of script termination) causes a fatal error.

In most cases you will get something like this:

PHP Fatal error: Exception thrown without a stack frame in Unknown on line 0

A good way is not reinvent this wheel and take e.g. Doctrine (http://www.doctrine-project.org/) to help you with this task. Even if you cannot use this piece of software you can have a look in the sources to learn how Benjamin does it. Look at the EntityManager (https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/EntityManager.php) and the UnitOfWork (https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/UnitOfWork.php), which relate to the handling you mentioned in you question.

like image 61
Mario Mueller Avatar answered Oct 27 '22 10:10

Mario Mueller