Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replaced all catch Exception with Throwable #1442

Closed
wants to merge 3 commits into from
Closed

Replaced all catch Exception with Throwable #1442

wants to merge 3 commits into from

Conversation

woutersamaey
Copy link
Contributor

@woutersamaey woutersamaey commented Feb 2, 2021

In PHP 5 the most generic thing to catch was Exception and Magento does this a lot. However with PHP7 and things like strict types, the most generic error to catch is now Throwable.

So, in this PR I've replaced 99% of the catch Exception with catch Throwable.
The only cases I didn't change are:

I hope this PR is appreciated, since it would greatly help the adoption of PHP7 and strict types, like I'm doing every day.

@github-actions github-actions bot added Component: AdminNotification Relates to Mage_AdminNotification Component: Adminhtml Relates to Mage_Adminhtml Component: Admin Relates to Mage_Admin Component: Api PageRelates to Mage_Api Component: Api2 Relates to Mage_Api2 Component: Authorizenet Relates to Mage_Authorizenet Component: Backup Relates to Mage_Backup Component: Bundle Relates to Mage_Bundle Component: Catalog Relates to Mage_Catalog Component: CatalogInventory Relates to Mage_CatalogInventory Component: CatalogRule Relates to Mage_CatalogRule Component: CatalogIndex Relates to Mage_CatalogIndex Component: CatalogSearch Relates to Mage_CatalogSearch Component: Centinel Relates to Mage_Centinel Component: Checkout Relates to Mage_Checkout Component: Cm/RedisSession Relates to Cm_RedisSession Component: ConfigurableSwatches Relates to Mage_ConfigurableSwatches Component: Contacts Relates to Mage_Contacts Component: Core Relates to Mage_Core Component: Cron Relates to Mage_Cron Component: CurrencySymbol Relates to Mage_CurrencySymbol Component: Customer Relates to Mage_Customer Component: Dataflow Relates to Mage_Dataflow Component: Directory Relates to Mage_Directory Component: Downloadable Relates to Mage_Downloadable Component: Eav Relates to Mage_Eav Component: ImportExport Relates to Mage_ImportExport Component: Index Relates to Mage_Index Component: Install Relates to Mage_Install labels Feb 2, 2021
@woutersamaey
Copy link
Contributor Author

@colinmollenhour
Copy link
Member

Thanks for the proposal, @woutersamaey!

Using RuntimeException seems like a mostly subjective change, what will it improve in the case of OpenMage?
I'm afraid it will create an unnecessary burden when reviewing pull requests, backporting or forward-porting patches, etc. Also I would argue that in a way Mage_Core_Exception is basically equivalent to RuntimeException so while it may have been standardized since, it is not really a new concept and is instead a redundant one.

This probably belongs in an RFC.. Please see the RFC template, I think this is the kind of discussion this change needs before it is accepted. I'm not so sure that a practice being recommended is a sufficient reason to make such sweeping changes. "They" also made PHP backwards compatible with the previous recommended practices so that existing projects would not be forced to adopt the new ones. :)

kkrieger85
kkrieger85 previously approved these changes May 12, 2021
Copy link
Contributor

@Flyingmana Flyingmana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

semantically seen, it seems wrong to catch and log exceptions for non-exceptions.

@luigifab
Copy link
Contributor

Some news?

@addison74
Copy link
Contributor

Before getting this merged we should discussed the PR #1434 too. At least we have the same way of handling exceptions adapted to the new variants of PHP.

luigifab
luigifab previously approved these changes Jun 10, 2022
Copy link
Contributor

@luigifab luigifab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In production for > 12 months.
But I think there are new Exception added.

kiatng
kiatng previously approved these changes Jun 10, 2022
@fballiano
Copy link
Contributor

Using RuntimeException seems like a mostly subjective change, what will it improve in the case of OpenMage? I'm afraid it will create an unnecessary burden when reviewing pull requests, backporting or forward-porting patches, etc. Also I would argue that in a way Mage_Core_Exception is basically equivalent to RuntimeException so while it may have been standardized since, it is not really a new concept and is instead a redundant one.

I agree with @colinmollenhour on this one. To have these many differences between v19 and v20 will make it really hard in the future. But since v19 will have to be bumped to something higher than php7.0 sometimes soon, would't it be ok to have this PR on v19 too?

@addison74
Copy link
Contributor

Let's rebase the PR to 19. Sury dropped this month the support for Debian 9 and you cannot install other PHP versions anymore. Debian 10 comes with 7.3 and Debian 11 with 7.4. We should not care about versions bellow 7.3.

@luigifab
Copy link
Contributor

luigifab commented Jul 6, 2022

I also vote for v19 😸.

@kiatng
Copy link
Contributor

kiatng commented Aug 18, 2022

I vote for v19. I just spent many minutes debugging an error because OM does not throw anything due to this:

} catch (Exception $e) {
ob_get_clean();
throw $e;
}

The error is thrown once I changed it to Throwable.

The offending code in my block:

    /**
     * @return bool
     */
    public function getCanWestEastTransfer()
    {
        return (bool) $this->getParentBlock()
            ->getCustomer()
            ->getCanWestEastTransfer();
    }

The page loaded without any error, but it is broken. After changing to Throwable, error is thrown, which should be expected:

Fatal error: Uncaught Error: Call to a member function getCanWestEastTransfer() on null

@colinmollenhour
Copy link
Member

My take currently:

  • I agree with changing Exception to Throwable where it is meant to catch the most generic error, but I don't think that is every location. For example there are places in controllers where the exception is caught, a somewhat generic error message added to the session and the exception is neither logged nor rethrown. In these cases the Throwable becomes harder to debug, not easier. Perhaps Throwable should only be caught in the platform code, not in models, blocks, helpers and controllers? This would let these truly unexpected errors bubble up to the platform code where it can always be logged.
  • Throwing exceptions with messages that are translated strings should be Mage_Core_Exception rather than RuntimeException, in my opinion.
  • I'm hesitant to approve this for v19 but will defer to others; as stated in another issue somewhere I would prefer the v19 discussion be a separate PR altogether after the v20 issue is merged to keep the considerations separate and avoid slowing what everyone agrees is good for v20 with the v19 discussion.

@addison74
Copy link
Contributor

addison74 commented Sep 19, 2022

I confirm what @kiatng said. I recently faced the implode function in an old PHTML file and the error did not appear anywhere. When I changed Exception to Throwable the error appeared in the browser window. Although I solved the issue without modification, I lost time to find it.

@luigifab
Copy link
Contributor

luigifab commented Nov 17, 2022

I have an issue with this PR.

With the PR, or simply by search and replace all catch (Exception /catch(Exception by catch (Throwable , or without this PR but by replacing only line 744 of Mage.php:

diff --git a/app/Mage.php b/app/Mage.php
index f1dd766a25..beb83314c4 100644
--- a/app/Mage.php
+++ b/app/Mage.php
@@ -734,21 +734,21 @@ final class Mage
                 'scope_type' => $type,
                 'options'    => $options,
             ]);
             Varien_Profiler::stop('mage');
         } catch (Mage_Core_Model_Session_Exception $e) {
             header('Location: ' . self::getBaseUrl());
             die();
         } catch (Mage_Core_Model_Store_Exception $e) {
             require_once(self::getBaseDir() . DS . 'errors' . DS . '404.php');
             die();
-        } catch (Exception $e) {
+        } catch (Throwable $e) { // here
             if (self::isInstalled()) {
                 self::printException($e);
                 exit();
             }
             try {
                 self::dispatchEvent('mage_run_exception', ['exception' => $e]);
                 if (!headers_sent() && self::isInstalled()) {
                     header('Location:' . self::getUrl('install'));
                 } else {
                     self::printException($e);

When you have an error in a template file, for example:

--- a/app/design/frontend/rwd/default/template/page/html/footer.phtml
+++ b/app/design/frontend/rwd/default/template/page/html/footer.phtml
@@ -17,6 +17,8 @@
  * @copyright   Copyright (c) 2006-2020 Magento, Inc. (https://www.magento.com)
  * @license     https://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
  */
+
+Mage:getIsDefault();
 ?>
 <div class="footer-container">
     <div class="footer">

When developer mode is enabled, the stack trace is wrong/incomplete:

Call to undefined function getIsDefault()

#0 .../app/code/core/Mage/Core/Block/Template.php(257): include()
#1 .../app/code/core/Mage/Core/Block/Template.php(291): Mage_Core_Block_Template->fetchView()
#2 .../app/code/core/Mage/Core/Block/Template.php(304): Mage_Core_Block_Template->renderView()
#3 .../app/code/core/Mage/Core/Block/Abstract.php(932): Mage_Core_Block_Template->_toHtml()
#4 .../app/code/core/Mage/Core/Block/Abstract.php(650): Mage_Core_Block_Abstract->toHtml()
#5 .../app/code/core/Mage/Core/Block/Abstract.php(594): Mage_Core_Block_Abstract->_getChildHtml()
#6 .../app/design/frontend/rwd/default/template/page/2columns-right.phtml(55): Mage_Core_Block_Abstract->getChildHtml()
#7 .../app/code/core/Mage/Core/Block/Template.php(257): include('...')
#8 .../app/code/core/Mage/Core/Block/Template.php(291): Mage_Core_Block_Template->fetchView()
#9 .../app/code/core/Mage/Core/Block/Template.php(304): Mage_Core_Block_Template->renderView()
#10 .../app/code/core/Mage/Core/Block/Abstract.php(932): Mage_Core_Block_Template->_toHtml()
#11 .../app/code/core/Mage/Core/Model/Layout.php(580): Mage_Core_Block_Abstract->toHtml()
#12 .../app/code/core/Mage/Core/Controller/Varien/Action.php(397): Mage_Core_Model_Layout->getOutput()
#13 .../app/code/core/Mage/Cms/Helper/Page.php(132): Mage_Core_Controller_Varien_Action->renderLayout()
#14 .../app/code/core/Mage/Cms/Helper/Page.php(48): Mage_Cms_Helper_Page->_renderPage()
#15 .../app/code/core/Mage/Cms/controllers/IndexController.php(39): Mage_Cms_Helper_Page->renderPage()
#16 .../app/code/core/Mage/Core/Controller/Varien/Action.php(428): Mage_Cms_IndexController->indexAction()
#17 .../app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(262): Mage_Core_Controller_Varien_Action->dispatch()
#18 .../app/code/core/Mage/Core/Controller/Varien/Front.php(188): Mage_Core_Controller_Varien_Router_Standard->match()
#19 .../app/code/core/Mage/Core/Model/App.php(371): Mage_Core_Controller_Varien_Front->dispatch()
#20 .../app/Mage.php(735): Mage_Core_Model_App->run()
#21 .../index.php(83): Mage::run()
#22 {main}

With the latest OpenMage without any changes, the stack trace is good:

Fatal error:  Uncaught Error: Call to undefined function getIsDefault() in .../app/design/frontend/rwd/default/template/page/html/footer.phtml:21
Stack trace:
#0 .../app/code/core/Mage/Core/Block/Template.php(257): include()
#1 .../app/code/core/Mage/Core/Block/Template.php(291): Mage_Core_Block_Template->fetchView()
#2 .../app/code/core/Mage/Core/Block/Template.php(304): Mage_Core_Block_Template->renderView()
#3 .../app/code/core/Mage/Core/Block/Abstract.php(932): Mage_Core_Block_Template->_toHtml()
#4 .../app/code/core/Mage/Core/Block/Abstract.php(650): Mage_Core_Block_Abstract->toHtml()
#5 .../app/code/core/Mage/Core/Block/Abstract.php(594): Mage_Core_Block_Abstract->_getChildHtml()
#6 .../app/design/frontend/rwd/default/template/page/2columns-right.phtml(55): Mage_Core_Block_Abstract->getChildHtml()
#7 .../app/code/core/Mage/Core/Block/Template.php(257): include('...')
#8 .../app/code/core/Mage/Core/Block/Template.php(291): Mage_Core_Block_Template->fetchView()
#9 .../app/code/core/Mage/Core/Block/Template.php(304): Mage_Core_Block_Template->renderView()
#10 .../app/code/core/Mage/Core/Block/Abstract.php(932): Mage_Core_Block_Template->_toHtml()
#11 .../app/code/core/Mage/Core/Model/Layout.php(580): Mage_Core_Block_Abstract->toHtml()
#12 .../app/code/core/Mage/Core/Controller/Varien/Action.php(397): Mage_Core_Model_Layout->getOutput()
#13 .../app/code/core/Mage/Cms/Helper/Page.php(132): Mage_Core_Controller_Varien_Action->renderLayout()
#14 .../app/code/core/Mage/Cms/Helper/Page.php(48): Mage_Cms_Helper_Page->_renderPage()
#15 .../app/code/core/Mage/Cms/controllers/IndexController.php(39): Mage_Cms_Helper_Page->renderPage()
#16 .../app/code/core/Mage/Core/Controller/Varien/Action.php(428): Mage_Cms_IndexController->indexAction()
#17 .../app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(262): Mage_Core_Controller_Varien_Action->dispatch()
#18 .../app/code/core/Mage/Core/Controller/Varien/Front.php(188): Mage_Core_Controller_Varien_Router_Standard->match()
#19 .../app/code/core/Mage/Core/Model/App.php(371): Mage_Core_Controller_Varien_Front->dispatch()
#20 .../app/Mage.php(735): Mage_Core_Model_App->run()
#21 .../index.php(83): Mage::run()
#22 {main}
  thrown in .../app/design/frontend/rwd/default/template/page/html/footer.phtml on line 21

Is someone know why?
I found, the second error is formatted by PHP.


Another side effect when we use set_exception_handler:

error_reporting(E_ALL);
ini_set('display_errors', 1);
set_exception_handler('handleException');

function handleException($e) {
	echo 'die:handleException: ',$e->getMessage(),"\n";
}

echo 'Test Throwable',"\n";
try {
	Mage::app();
}
catch (Throwable $e) {
	echo 'Exception: ',$e->getMessage(),"\n";
}

echo 'Test Exception',"\n";
try {
	Mage::app();
}
catch (Exception $e) {
	echo 'Exception: ',$e->getMessage(),"\n";
}

echo 'end',"\n";

Result for PHP 8.2, 8.1, 8.0, 7.4, 7.3, 7.2, 7.1, 7.0 is:

Test Throwable
Exception: Class "Mage" not found
Test Exception
die:handleException: Class "Mage" not found

The set_exception_handler is ignored for try catch Throwable.

@fballiano fballiano changed the base branch from 20.0 to 1.9.4.x December 19, 2022 11:31
@fballiano fballiano dismissed stale reviews from kiatng, luigifab, and kkrieger85 December 19, 2022 11:31

The base branch was changed.

@fballiano
Copy link
Contributor

I rebased on 1.9.4.x

@storefront-bvba storefront-bvba closed this by deleting the head repository Jan 19, 2023
@addison74
Copy link
Contributor

It seems that the author has closed this PR. I mark it with the label and if it is useful it can be proposed by someone else.

@luigifab
Copy link
Contributor

New PR or not?

@colinmollenhour
Copy link
Member

New PR or not?

I think a new PR is needed as a blanket replacement of all Exception with Throwable is probably not optimal and may not be an improvement. I think a new PR would need to spell out exactly what problems it is solving and why the specific approach was taken. That is, coder errors (e.g. type errors, calls to undefined functions) should not necessarily be handled the same as all other errors. Since there is already a "default error handler" registered, what needs to be fixed exactly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Admin Relates to Mage_Admin Component: Adminhtml Relates to Mage_Adminhtml Component: AdminNotification Relates to Mage_AdminNotification Component: Api PageRelates to Mage_Api Component: Api2 Relates to Mage_Api2 Component: Authorizenet Relates to Mage_Authorizenet Component: Backup Relates to Mage_Backup Component: Bundle Relates to Mage_Bundle Component: Catalog Relates to Mage_Catalog Component: CatalogIndex Relates to Mage_CatalogIndex Component: CatalogInventory Relates to Mage_CatalogInventory Component: CatalogRule Relates to Mage_CatalogRule Component: CatalogSearch Relates to Mage_CatalogSearch Component: Centinel Relates to Mage_Centinel Component: Checkout Relates to Mage_Checkout Component: Cm/RedisSession Relates to Cm_RedisSession Component: ConfigurableSwatches Relates to Mage_ConfigurableSwatches Component: Contacts Relates to Mage_Contacts Component: Core Relates to Mage_Core Component: Cron Relates to Mage_Cron Component: CurrencySymbol Relates to Mage_CurrencySymbol Component: Customer Relates to Mage_Customer Component: Dataflow Relates to Mage_Dataflow Component: Directory Relates to Mage_Directory Component: Downloadable Relates to Mage_Downloadable Component: Eav Relates to Mage_Eav Component: ImportExport Relates to Mage_ImportExport Component: Index Relates to Mage_Index Component: Install Relates to Mage_Install Component: lib/Mage Relates to lib/Mage Component: lib/Varien Relates to lib/Varien Component: lib/* Relates to lib/* Component: Log Relates to Mage_Log Component: Oauth Relates to Mage_Oauth Component: PageCache Relates to Mage_PageCache Component: Paygate Relates to Mage_Paygate Component: Payment Relates to Mage_Payment Component: PayPal Relates to Mage_Paypal Component: ProductAlert Relates to Mage_ProductAlert Component: Rating Relates to Mage_Rating Component: Reports Relates to Mage_Reports Component: Review Relates to Mage_Review Component: Rss Relates to Mage_Rss Component: Rule Relates to Mage_Rule Component: Sales Relates to Mage_Sales Component: SalesRule Relates to Mage_SalesRule Component: Sendfriend Relates to Mage_Sendfriend Component: Shipping Relates to Mage_Shipping Component: Sitemap Relates to Mage_Sitemap Component: Tag Relates to Mage_Tag Component: Tax Relates to Mage_Tax Component: Usa Relates to Mage_Usa Component: Widget Relates to Mage_Widget Component: Wishlist Relates to Mage_Wishlist Don't forget this PR Mage.php Relates to app/Mage.php shell Relates to shell scripts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants