एक कैच ब्लॉक में कई अपवाद प्रकारों को पकड़ना


244

मैं निम्न कार्यक्षमता प्राप्त करने के लिए, एक ब्लॉक में AErrorऔर पकड़ने के लिए एक क्लीनर तरीका चाहता हूं BError:

try
{
    /* something */
}
catch( AError, BError $e )
{
    handler1( $e )
}
catch( Exception $e )
{
    handler2( $e )
}

क्या इसे करने का कोई तरीका है? या मुझे उन्हें अलग से पकड़ना है?

AErrorऔर Berrorएक साझा आधार वर्ग है, लेकिन वे इसे अन्य प्रकारों के साथ भी साझा करते हैं जिन्हें मैं गिराना चाहता हूं handler2, इसलिए मैं बस आधार वर्ग को पकड़ नहीं सकता।


7
बस इसे एक साइड नोट के रूप में जोड़ने के लिए: एक RFC को कई अपवादों को पकड़ने के लिए दायर किया गया है। चलो देखते हैं कि क्या यह सुविधा PHP भाषा में है ... wiki.php.net/rfc/multiple-catch
SimonSimCity

10
^ यह फीचर PHP 7.1
Subin

जवाबों:


353

अपडेट करें:

PHP 7.1 के रूप में, यह उपलब्ध है।

वाक्य रचना है:

try
{
    // Some code...
}
catch(AError | BError $e)
{
    // Handle exceptions
}
catch(Exception $e)
{
    // Handle the general case
}

डॉक्स: https://www.php.net/manual/en/language.exception.php#example-287

RFC: https://wiki.php.net/rfc/multiple-catch

प्रतिबद्ध: https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a


7.1 से पहले PHP के लिए:

ये अन्य उत्तर क्या कहते हैं, इसके बावजूद आप पकड़ सकते हैं AErrorऔर BErrorउसी ब्लॉक में (यदि आप अपवादों को परिभाषित करते हैं तो यह कुछ आसान है)। यहां तक ​​कि यह भी कि ऐसे अपवाद हैं जिन्हें आप "के माध्यम से गिरना" चाहते हैं, आपको अभी भी अपनी आवश्यकताओं से मेल खाने के लिए एक पदानुक्रम को परिभाषित करने में सक्षम होना चाहिए।

abstract class MyExceptions extends Exception {}

abstract class LetterError extends MyExceptions {}

class AError extends LetterError {}

class BError extends LetterError {}

फिर:

catch(LetterError $e){
    //voodoo
}

जैसा कि आप यहां और यहां देख सकते हैं , यहां तक ​​कि SPLडिफ़ॉल्ट अपवादों में एक पदानुक्रम है जिसका आप लाभ उठा सकते हैं। इसके अतिरिक्त, जैसा कि PHP मैनुअल में कहा गया है :

जब एक अपवाद को फेंक दिया जाता है, तो कथन के बाद वाले कोड को निष्पादित नहीं किया जाएगा, और PHP पहले मिलान पकड़ने वाले ब्लॉक को खोजने का प्रयास करेगा।

इसका मतलब आप भी कर सकते थे

class CError extends LetterError {}

जिसे आपको अलग से संभालने की ज़रूरत है AErrorया BError, इसलिए आपका कैच स्टेटमेंट इस तरह दिखेगा:

catch(CError $e){
    //voodoo
}
catch(LetterError $e){
    //voodoo
}

यदि आपके पास ऐसा मामला था जहां बीस या अधिक अपवाद थे जो वैध रूप से एक ही सुपरक्लास के तहत थे, और आपको उनमें से पांच (या जो भी बड़े-ईश समूह) को संभालने की आवश्यकता थी और बाकी दूसरे, आप कर सकते हैं।

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}

और तब:

catch (Group1 $e) {}

जब अपवाद की बात आती है तो ओओपी का उपयोग करना बहुत शक्तिशाली है। जैसी चीजों का उपयोग करना get_classया instanceofहैक करना, और यदि संभव हो तो उन्हें टाला जाना चाहिए।

एक और समाधान जो मैं जोड़ना चाहूंगा, वह है अपवाद की हैंडलिंग कार्यक्षमता को अपनी विधि में रखना।

आप ऐसा कर सकते थे

function handleExceptionMethod1(Exception $e)
{
    //voodoo
}

function handleExceptionMethod2(Exception $e)
{
    //voodoo
}

मान लिया जाये कि वहाँ बिल्कुल कोई जिस तरह से आप अपवाद वर्ग पदानुक्रम या इंटरफेस को नियंत्रित कर सकते हैं (और वहाँ लगभग हमेशा होगा एक तरीका हो), तो आप निम्नलिखित कर सकते हैं:

try
{
    stuff()
}
catch(ExceptionA $e)
{
    $this->handleExceptionMethod1($e);
}
catch(ExceptionB $e)
{
    $this->handleExceptionMethod1($e);
}
catch(ExceptionC $e)
{
    $this->handleExceptionMethod1($e);
}
catch(Exception $e)
{
    $this->handleExceptionMethod2($e);
}

इस तरह, आपके पास अभी भी केवल एक ही कोड स्थान है जिसे आपको संशोधित करना है अगर आपके अपवाद हैंडलिंग तंत्र को बदलने की आवश्यकता है, और आप OOP के सामान्य निर्माणों के भीतर काम कर रहे हैं।


4
सही उत्तर के रूप में इसके लिए एक और वोट दिया गया है। दुर्भाग्य से सामान को स्वीकार किए गए उत्तर में कहा गया है और तथ्य यह है कि इसे सही उत्तर के रूप में स्वीकार किया जाता है, यह वही है जो PHP को पागलपन बनाता है।
borfast

यह स्वीकृत उत्तर होना चाहिए। हालाँकि, यह मानता है कि आप फ़ाइलों को संशोधित करने में सक्षम हैं। AErrorएक पुस्तकालय / फ़ाइल में लागू किया जा सकता है जिसे किसी तीसरे पक्ष द्वारा अद्यतन किया जाता है।
कायला

@ WaffleStealer654 आप अभी भी फ़ाइलों को हटा सकते हैं और उन लोगों को अपना समूह लागू कर सकते हैं, भले ही आप सीधे फ़ाइलों को संपादित नहीं कर सकते। ऐसा लगता है कि आप अपवादों को फेंक सकते हैं, लेकिन आप केवल सबसे आधार-स्तरीय तंत्र को लपेट सकते हैं जहां अपवाद को फेंक दिया जाएगा और फिर इसे पकड़ कर अपने लपेटे हुए अपवाद को फेंक सकते हैं।
दर्पण

3
यह स्वीकृत उत्तर नहीं है, क्योंकि आप ऐसा नहीं कर सकते जब आप तृतीय पक्ष लाइब्रेरी का उपयोग करते हैं।
डेनिस V

@DenisV आप के ऊपर मेरी टिप्पणी देखें। यह उद्यम सॉफ्टवेयर में हर समय किया जाता है। एनकैप्सुलेशन बहुत अच्छा है।
दर्पण

229

PHP में = = 7.1 यह संभव है। देखें इस सवाल का जवाब नीचे।


यदि आप अपवादों को संशोधित कर सकते हैं, तो इस उत्तर का उपयोग करें

यदि आप नहीं कर सकते हैं, तो आप सभी को पकड़ने की कोशिश कर सकते हैं Exceptionऔर फिर जांच कर सकते हैं कि किस अपवाद के साथ फेंक दिया गया था instanceof

try
{
    /* something */
}
catch( Exception $e )
{
    if ($e instanceof AError OR $e instanceof BError) {
       // It's either an A or B exception.
    } else {
        // Keep throwing it.
        throw $e;
    }
}

लेकिन यह शायद बेहतर होगा कि उपरोक्त उत्तर में वर्णित कई कैच ब्लॉक का उपयोग किया जाए

try
{
    /* something */
}
catch( AError $e )
{
   handler1( $e );
}
catch ( BError $b )
{
   handler2( $e );
}

6
यही मैं डरता था। उन्हें एक साथ पकड़ना और प्रकार का परीक्षण करना अच्छा होगा यदि कई त्रुटि प्रकार थे जिन्हें एक साथ संभालने की आवश्यकता थी, लेकिन केवल 2 के लिए, जैसे कि मेरे मामले में, उन्हें अलग से पकड़ना शायद क्लीनर है। धन्यवाद!
डोमिनिक Gurto

3
@DominicGurto: हाँ, मैं उसके साथ भी जाऊंगा :) मैं एक finallyबयान के प्रति PHP के रवैये से अधिक चिंतित हूँ । ;)
एलेक्स

7
लेकिन यह मत भूलो कि यह सभी अपवादों को पकड़ता है, इसलिए ऐसा कुछ होना चाहिए जैसे ... } else { throw($e); }कि यह दोनों से मेल नहीं खाता है। शायद गलत वाक्यविन्यास के लिए क्षमा करें, कुछ समय के लिए php नहीं देखा।
Dalibor Filus

11
यदि आप यहां पहला पैराग्राफ पढ़ते हैं: php.net/manual/en/language.exception.php आप देखेंगे कि कई कैच ब्लॉक संभव और पूरी तरह से वैध समाधान हैं। हालांकि ओपी ने गलती से दो अपवाद वर्गों को एक कैच स्टेटमेंट में डाल दिया था। मुझे लगता है कि कई कैच ब्लॉक के साथ अपने जवाब को दूसरे उदाहरण के साथ अपडेट करना बेहतर होगा।
हरलान डोबरेव

4
एक समाधान का सुझाव देना जो आपके सभी अन्य अपवादों को खाता है, इसे बिल्कुल स्वीकार नहीं किया जाना चाहिए ...
Stivni

88

PHP 7.1 में आना कई प्रकारों को पकड़ने की क्षमता है।

ताकि यह:

<?php
try {
    /* ... */
} catch (FirstException $ex) {
    $this->manageException($ex);
} catch (SecondException $ex) {
    $this->manageException($ex);
}
?>

तथा

<?php
try {

} catch (FirstException | SecondException $ex) {
    $this->manageException($ex);
}
?>

कार्यात्मक रूप से समतुल्य हैं।


45

PHP 7.1 के रूप में,

catch( AError | BError $e )
{
    handler1( $e )
}

दिलचस्प है, आप भी कर सकते हैं:

catch( AError | BError $e )
{
    handler1( $e )
} catch (CError $e){
    handler2($e);
} catch(Exception $e){
    handler3($e);
}

और PHP के पुराने संस्करणों में:

catch(Exception $ex){
    if($ex instanceof AError){
        //handle a AError
    } elseif($ex instanceof BError){
        //handle a BError
    } else {
       throw $ex;//an unknown exception occured, throw it further
    }
}

25

इस लेख में सवाल electrictoolbox.com/php-catch-multiple-exception-types शामिल हैं । लेख से सीधे कॉपी की गई पोस्ट की सामग्री:

उदाहरण अपवाद

यहाँ कुछ उदाहरण अपवाद हैं जिन्हें इस उदाहरण के प्रयोजनों के लिए परिभाषित किया गया है:

class FooException extends Exception 
{
  public function __construct($message = null, $code = 0) 
  {
    // do something
  }
}

class BarException extends Exception 
{
  public function __construct($message = null, $code = 0) 
  {
    // do something
  }
}

class BazException extends Exception 
{
  public function __construct($message = null, $code = 0) 
  {
    // do something
  }
}

कई अपवादों को संभालना

यह बहुत सरल है - प्रत्येक अपवाद प्रकार के लिए एक पकड़ ब्लॉक हो सकता है जिसे फेंका जा सकता है:

try 
{
  // some code that might trigger a Foo/Bar/Baz/Exception
}

catch(FooException $e) 
{
  // we caught a foo exception
}

catch(BarException $e) 
{
  // we caught a bar exception
}

catch(BazException $e) 
{
  // we caught a baz exception
}

catch(Exception $e) 
{
  // we caught a normal exception
  // or an exception that wasn't handled by any of the above
}

यदि एक अपवाद को फेंक दिया जाता है जो कि किसी भी अन्य कैच स्टेटमेंट द्वारा नियंत्रित नहीं किया जाता है तो इसे कैच द्वारा हैंडल किया जाएगा (अपवाद $ e) ब्लॉक। जरूरी नहीं कि वह आखिरी हो।


3
इस पद्धति के साथ समस्या तब आती है जब आपको दो या अधिक भिन्न अपवादों के लिए समान कोड निष्पादित करना होता है।
परिजीफल

यह इलेक्ट्रिक टूलबॉक्स से पुनर्प्राप्त किया गया था । क्रेडिट देने के लिए पोस्ट का संपादन।
कायला

PHP 7.x के साथ, आपको catch (Throwable $e)सभी अपवादों को पकड़ने की आवश्यकता है। इसे भी देखें: php.net/manual/en/class.throwable.php
Mikko Rantalainen

21

स्वीकृत उत्तर के विस्तार के रूप में, आप अपवाद के प्रकार को बदल सकते हैं जिसके परिणामस्वरूप एक पैटर्न है जो कुछ हद तक मूल उदाहरण की तरह है:

try {

    // Try something

} catch (Exception $e) {

    switch (get_class($e)) {

        case 'AError':
        case 'BError':
            // Handle A or B
            break;

        case 'CError':
            // Handle C
            break;

        case default:
            // Rethrow the Exception
            throw $e;

    }

}

6
इस समाधान के बजाय कई कैच का उपयोग करें।
एलेजांद्रो मोरेनो

5

यदि आप अपवादों को परिभाषित करने पर नियंत्रण नहीं रखते हैं तो यहां एक उचित विकल्प है। अपवाद चर के नाम का उपयोग अपवादों को वर्गीकृत करने के लिए करें जब वे पकड़े जाते हैं। फिर कोशिश / पकड़ ब्लॉक के बाद अपवाद चर के लिए जाँच करें।

$ABError = null;
try {
    // something
} catch (AError $ABError) {  // let the exception fall through
} catch (BError $ABError) {  // let the exception fall through
} catch (Exception $e) {
    handler2($e);
}
if ($ABError) {
    handler1($ABError);
}

यह कुछ हद तक अजीब लगने वाला दृष्टिकोण शायद केवल इसके लायक है यदि कैच ब्लॉक कार्यान्वयन के बीच बहुत अधिक दोहराव है।


3

फॉल-थ्रू के अलावा, गोटो का उपयोग करके भी कदम बढ़ाना संभव है । यह बहुत उपयोगी है अगर आप दुनिया को जलते हुए देखना चाहते हैं।

<?php

class A_Error extends Exception {}
class B_Error extends Exception {}
class C_Error extends Exception {}

try {
    throw new A_Error();
} 
catch (A_Error $e) { goto abc; }
catch (B_Error $e) { goto abc; }
catch (C_Error $e) {
abc:
    var_dump(get_class($e));
    echo "Gotta Catch 'Em All\n";
}

3v4l.org


1

एक शानदार तरीका उपयोग करना है set_exception_handler

चेतावनी !!! PHP 7 के साथ, आपको घातक त्रुटियों के लिए मौत की सफेद स्क्रीन मिल सकती है। उदाहरण के लिए, यदि आप गैर-ऑब्जेक्ट पर एक विधि कहते हैं, तो आप सामान्य रूप से प्राप्त Fatal error: Call to a member function your_method() on nullकरेंगे और यदि त्रुटि रिपोर्टिंग चालू है, तो आप इसे देखने की उम्मीद करेंगे।

उपरोक्त त्रुटि के साथ नहीं पकड़ा जाएगा catch(Exception $e)। उपरोक्त त्रुटि किसी भी कस्टम त्रुटि हैंडलर द्वारा ट्रिगर नहीं होगी set_error_handler

आपको catch(Error $e){ }PHP7 में त्रुटियों को पकड़ने के लिए उपयोग करना चाहिए । । यह मदद कर सकता है:

class ErrorHandler{
    public static function excep_handler($e)
    {
        print_r($e);
    }
}
set_exception_handler(array('ErrorHandler','excep_handler'));

1
... या आप बस लिख सकते हैं catch (Throwable $e) { ... }और इसके साथ किया जा सकता है। इसे भी देखें: php.net/manual/en/class.throwable.php
मिकीको रैंटलैनेन

0

एक अन्य विकल्प जो यहां सूचीबद्ध नहीं codeहै, वह एक अपवाद की विशेषता का उपयोग करना है, इसलिए आप ऐसा कुछ कर सकते हैं:

try {

    if (1 === $foo) {

         throw new Exception(sprintf('Invalid foo: %s', serialize($foo)), 1);
    }

    if (2 === $bar) {
        throw new Exception(sprintf('Invalid bar: %s', serialize($foo)), 2);
    }
} catch (Exception $e) {

    switch ($e->getCode()) {

        case 1:
            // Special handling for case 1
            break;

        case 2:
            // Special handling for case 2
            break;

        default:

            // Special handling for all other cases
    }
}

मैं नीचे नहीं गया, लेकिन शायद OOP के लोग इस बात से नाराज हैं कि आपने नए अपवाद वर्गों का उपयोग नहीं किया extends \Exception?
keyboardSmasher

समझ गया। यह मेरे समाधान का पूरा बिंदु है, आपको किसी विशिष्ट अपवाद को फेंकने के लिए एक नामस्थान स्थापित करने के लिए केवल मनमानी कक्षाएं बनाने की आवश्यकता नहीं है। Im निश्चित है कि उन्होंने एक कोड निर्दिष्ट करने की क्षमता क्यों जोड़ी है।
माइक पर्सल

मैं या तो नीचा नहीं था, लेकिन मुझे लगता है कि downvoters का मानना ​​है कि इस सवाल का जवाब नहीं है। मैं कुछ के साथ उत्तर शुरू करने का सुझाव दूंगा जिससे पाठक को यह स्पष्ट हो जाए कि आप प्रश्न को समझ गए हैं और आप अभी भी कोड प्रवाह के लिए कुल अलग तरीके का सुझाव देना चाहते हैं। यह जवाब वास्तव में "कई अपवाद प्रकारों को पकड़ने के लिए" का जवाब नहीं देता है , बल्कि "अपवाद के लिए कई अलग-अलग कारणों को कैसे संभालना है"।
मिकोको रैंटलैनेन

0

हम्म, 7.1 से कम php संस्करण के लिए लिखे गए कई समाधान हैं।

यहां उन लोगों के लिए एक और सरल है जो सभी अपवादों को नहीं पकड़ना चाहते हैं और आम इंटरफेस नहीं बना सकते हैं:

<?php
$ex = NULL
try {
    /* ... */
} catch (FirstException $ex) {
    // just do nothing here
} catch (SecondException $ex) {
    // just do nothing here
}
if ($ex !== NULL) {
    // handle those exceptions here!
}
?>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.