Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:88964 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 79379 invoked from network); 28 Oct 2015 13:29:03 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 28 Oct 2015 13:29:03 -0000 Authentication-Results: pb1.pair.com header.from=erik@evanv.nl; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=erik@evanv.nl; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain evanv.nl from 209.85.213.52 cause and error) X-PHP-List-Original-Sender: erik@evanv.nl X-Host-Fingerprint: 209.85.213.52 mail-vk0-f52.google.com Received: from [209.85.213.52] ([209.85.213.52:33287] helo=mail-vk0-f52.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 43/B1-63642-E9DC0365 for ; Wed, 28 Oct 2015 08:29:03 -0500 Received: by vkgy127 with SMTP id y127so4696095vkg.0 for ; Wed, 28 Oct 2015 06:28:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=evanv_nl.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=IT8i9HKAvJZJ9VNS32bnDyCHw5AYljjIbegejxVP7YI=; b=1/wsAZNGT6cDHAZmeJDZMVquWqPkFR+CtTS4FTnw2d0xyKAuX02Ca7eRaydaBs0M2L 4WtKHpoPD2RBN9PxdBcYRR3Vb9kIC2pP/cvA+SeYuyB32di3xWQ9a0tK7Hlu+5zTewNi kftcW2NGt/DUemlVa2Ke81VY+wMtSnGh8Wkq7/3RGO/ZOnFk2FuQNdH90Njo6Ycwmjfd VtZRKB/16D+3VoMDDxJgp4Ax45bsfrO8yWyKLa9yFkA3NNzxi57ghxHXA1DyWRqkeNLQ reXtUFSDpbKWpRyc0XjT5yOCCKOLl3h3k6FTIefH8wEFu+0ZGn3CWqeE35+U4ZGhgIjY G8Mg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:content-type; bh=IT8i9HKAvJZJ9VNS32bnDyCHw5AYljjIbegejxVP7YI=; b=OkX8KL3syFkJrDVQfdLPo+6rPb8gcXvNvdXMWtrPm4SK6CBJObSlbCIr2bUpbZ+HQr aalTmx14+2fcBhZ595a2qXnwlrkEYVVq/aL0YS4FlcJj1rR+X+vwpqkMzoC8QPuVxAvo m4AKfQY/i91t2kdHj66uUPYuz2ORpJ49gwZWrbbyaYtXvwWQ/u5KbKlK4zsmd5vjWQya KuNLEyTCM3AwTspzxoZwviu2aAGM6rqw1uj4A5wUkqPyD0V3O6TbcRw2252B2dP69xpo TMOxVQPISIMKK3bQy9Vyi+JGZb/F9oOPR3AxC/WBUjvuT97ruxXfAxjOWRL293i9PWHI 6IQA== X-Gm-Message-State: ALoCoQn5tVJKOnH0boIumraKf86PCHuqX1MY9SGWaa0cwJqVDwF5d+Xdfw/zF4t4lmuMwXiT2pPt MIME-Version: 1.0 X-Received: by 10.31.130.71 with SMTP id e68mr19106139vkd.11.1446038939137; Wed, 28 Oct 2015 06:28:59 -0700 (PDT) Received: by 10.31.92.83 with HTTP; Wed, 28 Oct 2015 06:28:59 -0700 (PDT) X-Originating-IP: [84.243.196.9] In-Reply-To: References: Date: Wed, 28 Oct 2015 14:28:59 +0100 Message-ID: To: internals@lists.php.net Content-Type: text/plain; charset=UTF-8 Subject: Re: [PHP-DEV] In a destructor, how to detect if an exception is currently in flight? From: erik@evanv.nl (Erik van Velzen) Thanks for your input. I did not try-catch because it doesn't really work, you either duplicate rollback code or get excessive nesting. Real code will obviously be more complicated than the examples. Also in both cases the handlers are many lines apart from the actual transaction call. Duplicate rollback code: try { transactionOne(); } catch (\Throwable $e) { rollbackTransactionOne(); throw $e; } try { transactionTwo(); } catch (\Throwable $e) { rollbackTransactionOne(); rollbackTransactionTwo(); throw $e; } finally { cleanupTransactionTwo(); } try { transactionThree(); } catch (\Throwable $e) { rollbackTransactionOne(); rollbackTransactionTwo(); rollbackTransactionThree(); throw $e; } logTransactionOne(); logTransactionTwo(); logTransactionThree(); Excessive nesting: try { transactionOne() try { transactionTwo(); try { transactionThree(); } catch (\Throwable $e) { rollbackTransactionThree() throw $e; } } catch (\Throwable $e) { rollbackTransactionTwo(); throw $e; } finally { cleanupTransactionTwo(); } } catch (\Throwable $e) { rollbackTransactionOne(); throw $e; } But you did help me very well with your second example because I can put a single try-catch over the entire thing and indeed do the optional callbacks at the end: try { $scope = new ScopeGuard; $scope->onSucces(function() { logTransactionOne(); }); $scope->onFailure(function() { rollbackTransationOne(); }); doTransactionOne(); $scope->onSuccess(function() { logTransactionTwo(); }); $scope->onFailure(function() { rollbackTransactionTwo(); }); $scope->onExit(function() { cleanupTransactionTwo(); }); doTransactionTwo(); } catch (\Throwable $e) { $scope->callFailureHandlers(); throw $e; } finally { $scope->callExitHandlers(); } $scope->callSuccessHandlers(); This suffices as far as duplicate code and nesting go. But the last few lines are always the same, and this is a common pattern. Perhaps this can be encapsulated somehow (IoC)? Destructors seem like a good fit but it seems the engine does not have the necessary hook. Maybe we can let the ScopeGuard object itself execute the code? Like this: class ScopeGuard { public static function execute(closure $code) { try { $scope = new self; $result = $code($scope); $scope->executeSuccessHandlers(); } catch(\Throwable $e) { $scope->executeFailureHandlers(); throw $e; } finally { $scope->executeExitHandlers(); } return $result; } public function onFailure($callable) {} public function onSuccess($callable) {} public function onExit($callable) {} } ScopeGuard::execute(function(ScopeGuard $scope) { /* same linear transaction code here as above, but without try-catch */ }); Not sure on this one. It restricts you to use a single ScopeGuard at a time. I might make a library for it though. 2015-10-28 12:24 GMT+01:00 Leigh : > > > Why don't you catch the exception? (You can always re-throw it if you want > to do something when there is an exception, but don't want to handle it > yourself) > > try { > doTransactionOne(); > logTransactionOne(); > } > catch (\Throwable $e) { > rollbackTransationOne(); > throw $e; > } > > Or if you really want to use your scope thingy. > > try { > doTransactionOne(); > } > catch (\Throwable $e) { > $scope->abortedDueToException(); > throw $e; > } >