Высвобождение переменных при эксепшене [Фудаментальный вопрос разработчикам PHP]

NT Man

Новичок
Как вы считаете должны ли уничтожатся все переменные, которые станут недоступны при выкидывании исключения?

продемонстрирую на примере:

PHP:
#!/usr/bin/php
<?php
    error_reporting(E_ALL);
    ini_set('display_errors','On');
    function inner_fn1($db) {
        $sth = $db->query('select 1; select 2');
        inner_fn2($sth);
    }
    function inner_fn2($sth) {
        $data = $sth->fetchAll(PDO::FETCH_ASSOC);
        throw new exception ('some error');
        unset($sth);
    }
    $attr = array(
        PDO::ATTR_PERSISTENT => true
        ,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
        //,PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
        ,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        );

    $db = new PDO('mysql:dbname=BPLnew;unix_socket=/var/lib/mysql/mysql.sock','root','', $attr);
    $db->query('START TRANSACTION');
   
    try {
        inner_fn1($db);
    } catch(Exception$e) {
        echo("$e\n");
        echo("============================================================\n");
        //$sth->closeCursor();
        //unset($sth);
        //$db->free();
        $db->query('ROLLBACK');
    }
  $db->query('ROLLBACK');
?>

Если в функции inner_fn2 выкинуть exception, то поидее $sth созданный в inner_fn1 будет недоступен в обработчике исключения, который по вложенности кода расположен выше. На это можно было бы забить, если ни одно очень большое НО. Дело в том, что в обработчике исключения мы что-то делаем с базой дальше. В конкретном примере ролбачим базу, но там может быть все что угодно. И тут оказывается, что мы это сделать не можем из-за того, что база ждет когда мы получим от неё все резалтсеты. А мы их не получить не можем ни за ансетить из за того что гдето до этого взорвался эксепшен.

Решения тут вижу два. Либо имплементироваровать чтонибудь в PDO для принудительного охлаждения базы, либо заставить ядро PHP правильно освобождать память. По мне так первый вариант костыль, но при должном усердии я его смогу реализовать, но не факт, что его примут в апстим. что думаете насчет второго варианта? Я сразу говорю я там пас, нужен чел который хорошо разбирается в ядре, чтобы однозначно ответить почему PHP так не делает сейчас и возможно ли его заставить так делать.
 

NT Man

Новичок
а тут даже не в нем дело можно закоменить всеравно вылетит на ролбаке.

Это конечно к данному топику не имеет никакого отношения но всеже спрошу почему зло? По логике вещей то чем реже делаем однотипные действия. те же самые переподключения к базе тем по логике же лучше.
 

NT Man

Новичок
Программирование тоже зло ;)

А что должно быть в finally?
Ничего что ловля исключений идет в пространстве видимости где не видно, $sth? Понятно что можно данный пример переписать так что $sth будет виден или ловить эксепшн внутри inner_fn1, но пример был создан специально чтоб показать проблему. Потомучто имея её нельзя говорить о том что в PHP нельзя себе выстрелить в ногу, еще как можно, да еще в неочевидной манере. Когда подвох там ну где его совсем не ждешь.
 

Фанат

oncle terrible
Команда форума
а если убить соединение - роллбек произойдет автоматически, как должен по идее?
 

NT Man

Новичок
а если убить соединение - роллбек произойдет автоматически, как должен по идее?
Если ловить исключения так
PHP:
    } catch(Exception$e) {
        echo("$e\n");
        echo("============================================================\n");
        //$sth->closeCursor();
        //unset($sth);
        //$db->free();
        unset($db);
        $db = new PDO('mysql:dbname=BPLnew;unix_socket=/var/lib/mysql/mysql.sock','root','', $attr);
        //$db->query('ROLLBACK');
    }
то ничего в базу не запишется.
Ну вопервых как я писал выше 'ROLLBACK' тут тоже для примера. А может надо сделать ROLLBACK TO SAVEPOINT ????
Ну и делать unset($db); это уж совем по быдлокодерски.
 

Redjik

Джедай-мастер
А может надо сделать ROLLBACK TO SAVEPOINT ????
Эти знания должны хранится в отдельном объекте с публичным rollback

по освобождению памяти - можно issue создать попробовать, штука нужная
надо реализацию стека в PHP покопать
 

WMix

герр M:)ller
Партнер клуба
вроде сам предложил.. не так и сложно же обернуть?
PHP:
function inner_fn1($db) {
        try{
            $sth = $db->query('select 1; select 2');
            inner_fn2($sth);
        }
        catch( Exception $e ) {
            $sth->closeCursor();
            throw $e;
        }
    }
хотя соглашусь, не царское это дело
 
Последнее редактирование:

MiksIr

miksir@home:~$
Для освобождения память есть gc. Я честно не понял, о чем топик? У вас не проходит rollback? А пробовали все же $db->beginTransaction() и $db->rollback() ?
 
Сверху