ব্যতিক্রমগুলি ধরার এবং পুনরায় নিক্ষেপের সেরা অনুশীলনগুলি কী কী?


156

ধরা পড়া ব্যতিক্রমগুলি সরাসরি আবার ছুঁড়ে ফেলা উচিত, না তাদের নতুন ব্যতিক্রমকে জড়িয়ে রাখা উচিত?

এটি হ'ল, আমি কি এটি করব:

try {
  $connect = new CONNECT($db, $user, $password, $driver, $host);
} catch (Exception $e) {
  throw $e;
}

অথবা এটা:

try {
  $connect = new CONNECT($db, $user, $password, $driver, $host);
} catch (Exception $e) {
  throw new Exception("Exception Message", 1, $e);
}

যদি আপনার উত্তরটি সরাসরি ছুঁড়ে ফেলা হয় তবে দয়া করে ব্যতিক্রম শৃঙ্খলার ব্যবহারের পরামর্শ দিন , আমি এমন এক বাস্তব বিশ্বের পরিস্থিতি বুঝতে সক্ষম হই না যেখানে আমরা ব্যতিক্রম শৃঙ্খলা ব্যবহার করি।

উত্তর:


287

আপনি অর্থবহ কিছু করার ইচ্ছা না করেই আপনি ব্যতিক্রমটি ধরবেন না

"অর্থপূর্ণ কিছু" এর মধ্যে একটি হতে পারে:

ব্যতিক্রম হ্যান্ডেলিং

সর্বাধিক সুস্পষ্ট অর্থবোধক ক্রিয়াটি ব্যতিক্রমটি পরিচালনা করা, যেমন কোনও ত্রুটি বার্তা প্রদর্শন করে এবং অপারেশনটি বাতিল করে দেওয়া:

try {
    $connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
    echo "Error while connecting to database!";
    die;
}

লগিং বা আংশিক পরিষ্কার

কখনও কখনও আপনি নির্দিষ্ট প্রসঙ্গের মধ্যে কীভাবে একটি ব্যতিক্রমটি সঠিকভাবে পরিচালনা করবেন তা জানেন না; সম্ভবত "বড় ছবি" সম্পর্কে আপনার অভাব রয়েছে, তবে আপনি ব্যর্থতাটি যতটা সম্ভব ঘটেছে তার ঠিক কাছেই লগ করতে চান। এই ক্ষেত্রে, আপনি ধরা, লগ এবং পুনরায় নিক্ষেপ করতে চাইতে পারেন:

try {
    $connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
    logException($e); // does something
    throw $e;
}

সম্পর্কিত পরিস্থিতি হ'ল ব্যর্থ ক্রিয়াকলাপের জন্য কিছু পরিষ্কার করার জন্য আপনি যেখানে সঠিক জায়গায় রয়েছেন, কিন্তু ব্যর্থতা কীভাবে শীর্ষ স্তরে পরিচালনা করা উচিত তা সিদ্ধান্ত নেওয়া হয়নি। পূর্ববর্তী পিএইচপি সংস্করণগুলিতে এটি হিসাবে প্রয়োগ করা হবে

$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
    $connect->insertSomeRecord();
}
catch (Exception $e) {
    $connect->disconnect(); // we don't want to keep the connection open anymore
    throw $e; // but we also don't know how to respond to the failure
}

পিএইচপি 5.5 finallyকীওয়ার্ডটি চালু করেছে , তাই সাফের দৃশ্যপটের জন্য এখন আরও একটি উপায় রয়েছে এটির কাছে যাওয়ার জন্য। যদি ক্লিনআপ কোডটি যা ঘটেছিল তা চালানোর প্রয়োজন নেই (যেমন ত্রুটি এবং সাফল্য উভয়ই) কোনও নিক্ষিপ্ত ব্যতিক্রম প্রচারের স্বচ্ছতার সাথে করে এখন এটি করা সম্ভব:

$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
    $connect->insertSomeRecord();
}
finally {
    $connect->disconnect(); // no matter what
}

ত্রুটি বিমূর্তকরণ (ব্যতিক্রম শৃঙ্খলা সহ)

তৃতীয় কেস হ'ল যেখানে আপনি যুক্তিসঙ্গতভাবে একটি বড় ছাতার নিচে সম্ভাব্য অনেকগুলি ব্যর্থতা গোষ্ঠী করতে চান। যৌক্তিক গোষ্ঠীকরণের জন্য একটি উদাহরণ:

class ComponentInitException extends Exception {
    // public constructors etc as in Exception
}

class Component {
    public function __construct() {
        try {
            $connect = new CONNECT($db, $user, $password, $driver, $host);
        }
        catch (Exception $e) {
            throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);
        }
    }
}

এই ক্ষেত্রে, আপনি ব্যবহারকারীদের Componentএটি জানতে চান না যে এটি একটি ডেটাবেস সংযোগ ব্যবহার করে প্রয়োগ করা হয়েছে (সম্ভবত আপনি আপনার বিকল্পগুলি উন্মুক্ত রাখতে চান এবং ভবিষ্যতে ফাইল-ভিত্তিক স্টোরেজ ব্যবহার করতে চান)। সুতরাং আপনার স্পেসিফিকেশনটি Componentবলবে যে "একটি সূচনা ব্যর্থতার ক্ষেত্রে ComponentInitExceptionনিক্ষেপ করা হবে"। এটি গ্রাহকরা Componentপ্রত্যাশিত ধরণের ব্যতিক্রমগুলি ধরতে পারবেন এবং ডিবাগিং কোডকে সমস্ত (প্রয়োগ-নির্ভর) বিশদটি অ্যাক্সেস করার অনুমতি দেবেন

সমৃদ্ধ প্রসঙ্গ সরবরাহ করা (ব্যতিক্রম শৃঙ্খলা সহ)

অবশেষে, এমন কেস রয়েছে যেখানে আপনি ব্যতিক্রমের জন্য আরও প্রসঙ্গ সরবরাহ করতে চাইতে পারেন। এক্ষেত্রে এটি ব্যতিক্রমটিকে অন্য একটিতে গুটিয়ে ফেলা বোধগম্য হয় যা ত্রুটি হওয়ার সময় আপনি কী করার চেষ্টা করেছিলেন সে সম্পর্কে আরও তথ্য ধারণ করে। উদাহরণ স্বরূপ:

class FileOperation {
    public static function copyFiles() {
        try {
            $copier = new FileCopier(); // the constructor may throw

            // this may throw if the files do no not exist
            $copier->ensureSourceFilesExist();

            // this may throw if the directory cannot be created
            $copier->createTargetDirectory();

            // this may throw if copying a file fails
            $copier->performCopy();
        }
        catch (Exception $e) {
            throw new Exception("Could not perform copy operation.", 0, $e);
        }
    }
}

এই কেসটি উপরের মতই (এবং উদাহরণটি সম্ভবত সেরাটি সামনে আসতে পারে নি) তবে এটি আরও প্রসঙ্গ সরবরাহ করার বিষয়টি চিত্রিত করে: যদি কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হয়, তবে এটি আমাদের জানায় যে ফাইলের অনুলিপি ব্যর্থ হয়েছে। তবে কেন ব্যর্থ হল? এই তথ্যটি মোড়ানো ব্যতিক্রমগুলিতে সরবরাহ করা হয় (যার মধ্যে উদাহরণটি আরও জটিল হলে একাধিক স্তর থাকতে পারে)।

এটি করার মানটি উদাহরণস্বরূপ যদি আপনি এমন কোনও দৃশ্যের কথা চিন্তা করেন যেখানে কোনও UserProfileবস্তু তৈরি করা ফাইলগুলি অনুলিপি করে দেয় কারণ ব্যবহারকারী প্রোফাইল ফাইলগুলিতে সঞ্চিত থাকে এবং এটি লেনদেন শব্দার্থকে সমর্থন করে: আপনি পরিবর্তনগুলি "পূর্বাবস্থায়" ফেলতে পারেন কারণ সেগুলি কেবলমাত্র একটিতে সম্পাদিত হয় আপনার প্রতিশ্রুতি না দেওয়া পর্যন্ত প্রোফাইলের অনুলিপি।

এই ক্ষেত্রে, আপনি যদি

try {
    $profile = UserProfile::getInstance();
}

এবং ফলস্বরূপ একটি "টার্গেট ডিরেক্টরি তৈরি করা যায়নি" ব্যতিক্রম ত্রুটি, আপনার বিভ্রান্ত হওয়ার অধিকার থাকবে। প্রসঙ্গটি সরবরাহ করে এমন অন্যান্য ব্যতিক্রমের স্তরগুলিতে এই "মূল" ব্যতিক্রমটি মুড়িয়ে ফেলা ত্রুটিটিকে মোকাবেলা করা আরও সহজ করে দেবে ("প্রোফাইলের অনুলিপি তৈরি করা ব্যর্থ হয়েছে" -> "ফাইল অনুলিপি অপারেশন ব্যর্থ হয়েছে" -> "টার্গেট ডিরেক্টরি তৈরি করা যায়নি")।


আমি কেবল শেষ 2 কারণে একমত: 1 / ব্যতিক্রম পরিচালনা: আপনার এই স্তরে এটি করা উচিত নয়, 2 / লগিং বা ক্লিনআপ: অবশেষে ব্যবহার করুন এবং ব্যতিক্রমটি আপনার ডেটালেয়ারের উপরে লগ করুন
রিমি বার্গারেল

1
@ রেমি: পিএইচপি বাদে এই finallyনির্মাণকে সমর্থন করে না (এখনও কমপক্ষে নয়) ... সুতরাং এটি শেষ, যার অর্থ আমাদের অবশ্যই এই জাতীয়
জঞ্জাল

@ রেমিবার্গারেল: ১: এটি কেবল একটি উদাহরণ ছিল। অবশ্যই আপনার এই স্তরে এটি করা উচিত নয়, তবে উত্তরটি হিসাবে এটি যথেষ্ট দীর্ঘ। 2: @ কিরম্যাক্সেল যেমন বলেছে, finallyপিএইচপি-তে নেই।
জন

3
অবশেষে, পিএইচপি 5.5 এখন অবশেষে প্রয়োগ করে।
ওসিডিভ

12
আমার মনে হয় যে এখানে আপনি নিজের তালিকা থেকে মিস করেছেন - এর একটি কারণ রয়েছে - আপনি এটি ব্যর্থ করতে না পারছেন না, যতক্ষণ না আপনি এটি ধরেন এবং পরীক্ষা করার সুযোগ না পাওয়া পর্যন্ত আপনি এটি পরিচালনা করতে পারবেন কিনা tell উদাহরণস্বরূপ, নিম্ন-স্তরের এপিআইয়ের একটি মোড়ক যা ত্রুটি কোডগুলি ব্যবহার করে (এবং এর মধ্যে কয়েক মিলিয়ন রয়েছে) একটি একক ব্যতিক্রম শ্রেণি থাকতে পারে যা এটি কোনও ত্রুটির জন্য একটি উদাহরণ ছুঁড়ে দেয়, এমন কোনও error_codeসম্পত্তি যা অন্তর্নিহিত ত্রুটি পাওয়ার জন্য পরীক্ষা করা যায় কোড। যদি আপনি কেবলমাত্র ত্রুটিগুলি অর্থপূর্ণভাবে পরিচালনা করতে সক্ষম হন তবে আপনি সম্ভবত ধরতে চান, পরিদর্শন করতে পারেন এবং যদি আপনি ত্রুটিটি পরিচালনা করতে না পারেন - পুনর্বিবেচনা করুন।
মার্ক এ Amery

37

ঠিক আছে, এটি বিমূর্ততা বজায় রাখা সম্পর্কে। তাই আমি সরাসরি নিক্ষেপ করতে ব্যতিক্রম শৃঙ্খলা ব্যবহার করার পরামর্শ দেব। যতদূর কেন, আমি ফাঁসী বিমূর্ততা ধারণাটি ব্যাখ্যা করি

ধরা যাক আপনি একটি মডেল তৈরি করছেন। মডেলটির বাকী অ্যাপ্লিকেশন থেকে সমস্ত ডেটা অধ্যবসায় এবং বৈধতা দূরে রাখার কথা। সুতরাং এখন আপনি যখন একটি ডাটাবেস ত্রুটি পেতে হবে? আপনি যদি পুনর্নির্মাণ করেন তবে আপনি বিমূর্ততা ফাঁস DatabaseQueryExceptionকরছেন। কেন তা বুঝতে, এক সেকেন্ডের জন্য বিমূর্ততা সম্পর্কে ভাবুন। মডেল কীভাবে ডেটা সঞ্চয় করে তা আপনার যত্নশীল নয় । একইভাবে আপনি মডেলটির অন্তর্নিহিত সিস্টেমগুলিতে ঠিক কী ভুল হয়েছে সেদিকে খেয়াল রাখেন না, কেবল আপনি জানেন যে কিছু ভুল হয়েছে এবং আনুমানিক কী ভুল হয়েছে।

সুতরাং ডেটাবেসকিউরিএক্সেপশন পুনর্বিবেচনা করে আপনি বিমূর্ততা ফাঁস করছেন এবং মডেলটির অধীনে কী চলছে তার শব্দার্থকতা বোঝার জন্য কলিং কোডের প্রয়োজন। পরিবর্তে, একটি জেনেরিক তৈরি করুন ModelStorageException, এবং এর DatabaseQueryExceptionভিতরে ধরা জড়ান । এইভাবে, আপনার কলিং কোডটি ত্রুটিটি শব্দার্থতভাবে মোকাবেলা করার চেষ্টা করতে পারে তবে মডেলটির অন্তর্নিহিত প্রযুক্তিটি কোনও বিষয় নয় কারণ আপনি কেবলমাত্র এটি বিমূর্ত স্তরটি থেকে ত্রুটি প্রকাশ করছেন। আরও ভাল, যেহেতু আপনি ব্যতিক্রমটি মুড়ে ফেলেছেন, যদি এটি সমস্তভাবে বুদবুদ হয় এবং লগ করার প্রয়োজন হয় তবে আপনি নিক্ষেপ করা মূল ব্যতিক্রমটি সনাক্ত করতে পারেন (চেইনটি হাঁটা) যাতে আপনার এখনও প্রয়োজনীয় সমস্ত ডিবাগিং তথ্য থাকে!

আপনার কিছু পোস্ট-প্রসেসিং করার প্রয়োজন না হলে কেবল একই ব্যতিক্রমটিকে ধরা এবং পুনর্বিবেচনা করবেন না। তবে এর মতো একটি ব্লক } catch (Exception $e) { throw $e; }অর্থহীন। তবে আপনি কিছু উল্লেখযোগ্য বিমূর্ততা লাভের জন্য ব্যতিক্রমগুলি পুনরায় মোড়ানো করতে পারেন।


2
দুর্দান্ত উত্তর। স্ট্যাক ওভারফ্লো (উত্তরগুলির উপর ভিত্তি করে) আশেপাশে বেশ কিছু লোক মনে হচ্ছে তাদের ভুল ব্যবহার করছে।
জেমস

8

আইএমএইচও, কেবল পুনর্বিবেচনার জন্য একটি ব্যতিক্রম ধরা এটি অকেজো । এই ক্ষেত্রে, কেবল এটি ধরবেন না, এবং পূর্ববর্তী কলিত পদ্ধতিগুলি এটি পরিচালনা করতে দেয় (কল স্ট্যাকের 'ওপরের' ওরফে পদ্ধতিগুলি)

যদি আপনি এটি পুনর্বিবেচনা করেন, তবে আপনি যে নতুনটিকে ফেলেছেন তার মধ্যে ধরা পড়া ব্যতিক্রমটিকে শৃঙ্খলাবদ্ধ করা অবশ্যই একটি ভাল অনুশীলন, কারণ এটি ধরা পড়া ব্যতিক্রমের মধ্যে থাকা তথ্যগুলি রাখবে keep তবে, এটি পুনর্বিবেচনা কেবলমাত্র দরকারী যদি আপনি কিছু তথ্য যোগ করেন বা ধরা ব্যতিক্রম কিছু হ্যান্ডেল করেন , এটি কিছু প্রসঙ্গ, মান, লগিং, নিখরচায় সংস্থানগুলি যাই হোক না কেন হতে পারে।

একটি উপায় কিছু তথ্য যোগ করার জন্য বাড়ানো Exception, বর্গ মত ব্যতিক্রম আছে NullParameterException, DatabaseExceptionইত্যাদি আরো বেশি, এই developper শুধুমাত্র কিছু ব্যতিক্রম যে, তিনি সব ব্যবস্থা করতে সক্ষম ধরা করার অনুমতি দেয়। উদাহরণস্বরূপ, কেউ কেবল ধরা পড়তে পারে এবং ডেটাবসের সাথে পুনরায় সংযোগ স্থাপনের মতো DatabaseExceptionকী ঘটেছিল তা সমাধান করার চেষ্টা করতে পারে Exception


2
এটি অকেজো নয়, এমন সময় রয়েছে যখন আপনি কিছু ব্যতিক্রম ব্যতীত কিছু করতে হবে যাতে ফাংশনটিতে এটি নিক্ষেপ করে এবং তারপরে একটি উচ্চতর আপকে অন্য কিছু করতে দেওয়ার জন্য এটিকে আবার ফেলে দেয়। আমি যে প্রকল্পে কাজ করছি তার মধ্যে আমরা কখনও কখনও কোনও অ্যাকশন পদ্ধতিতে একটি ব্যতিক্রম ধরা করি, ব্যবহারকারীর কাছে বন্ধুত্বপূর্ণ নোটিশ প্রদর্শন করি এবং তারপরে আবার নিক্ষেপ করি যাতে কোডটিতে আরও চেষ্টা করার পরে ব্লকটি আবার ত্রুটিটি লগইন করতে পারে একটি লগ.
মিটমারো

1
সুতরাং আমি যেমন বলেছি, আপনি ব্যতিক্রম কিছু তথ্য যুক্ত করুন (একটি নোটিশ প্রদর্শন, এটি লগ ইন)। আপনি কেবল ওপি-র উদাহরণ হিসাবে এটি পুনর্বিবেচনা করবেন না ।
ক্লিমেন্ট হেরেম্যান

2
ঠিক আছে, আপনার যদি সংস্থানগুলি বন্ধ করার দরকার হয় তবে আপনি এটি পুনর্বিবেচনা করতে পারেন তবে যুক্ত করার জন্য কোনও অতিরিক্ত তথ্য নেই। আমি একমত যে এটি বিশ্বের সবচেয়ে পরিষ্কার জিনিস নয়, তবে এটি ভয়াবহ
ইরকমেক্সেল

2
@ ক্যারম্যাক্সেল সম্মত হয়েছেন, এটি প্রতিফলিত করার জন্য সম্পাদিত আপনি যদি কেবল নতুন করে বাদ দিয়ে কিছু না করেন
হেরেম্যান

1
গুরুত্বপূর্ণ বিটটি হ'ল আপনি ফাইলটি এবং / অথবা লাইন তথ্যটি যেখানে ব্যতিক্রমটি মূলত এটি পুনরায় নিক্ষেপ করে ফেলেছিল তা আলগা করে। সুতরাং সাধারণত কোনও নতুনকে টানা এবং পুরানোটিকে পাশ কাটিয়ে দেওয়া ভাল, যেমন প্রশ্নের দ্বিতীয় উদাহরণের মতো। অন্যথায় এটি কেবল ক্যাচ ব্লকের দিকে ইঙ্গিত করবে, প্রকৃত সমস্যাটি কী হয়েছে তা অনুমান করে।
ড্যানম্যান

2

আপনাকে পিএইচপি 5.3ব্যতিক্রমী সেরা অভ্যাসগুলি একবার দেখে নিতে হবে

পিএইচপি-তে ব্যতিক্রম হ্যান্ডলিং কোনও প্রসারিত দ্বারা নতুন বৈশিষ্ট্য নয়। নিম্নলিখিত লিঙ্কে, আপনি ব্যতিক্রমগুলির উপর ভিত্তি করে পিএইচপি 5.3 এ দুটি নতুন বৈশিষ্ট্য দেখতে পাবেন। প্রথমটি নেস্টেড ব্যতিক্রম এবং দ্বিতীয়টি এসপিএল এক্সটেনশন (যা এখন পিএইচপি রানটাইমের মূল প্রসারিত) দ্বারা প্রস্তাবিত ব্যতিক্রম ধরণের একটি নতুন সেট। এই দুটি নতুন বৈশিষ্ট্যই সেরা সেরা অনুশীলনের বইটিতে তাদের পথ খুঁজে পেয়েছে এবং বিশদভাবে তা পরীক্ষা করার যোগ্য।

http://ralphschindler.com/2010/09/15/exception-best-practices-in-php-5-3


1

আপনি সাধারণত এটি এইভাবে ভাবেন।

একটি শ্রেণি মেলে না এমন অনেক ধরণের ব্যতিক্রম ছুঁড়ে ফেলতে পারে। সুতরাং আপনি যে শ্রেণীর বা শ্রেণীর ধরণের জন্য একটি ব্যতিক্রম শ্রেণি তৈরি করেন এবং তা ফেলে দিন।

সুতরাং ক্লাসটি ব্যবহার করে এমন কোডটি কেবল এক ধরণের ব্যতিক্রম ধরতে হবে।


1
আরে আপনি কি আরও কিছু বিশদ বা একটি লিঙ্ক প্রদান করতে পারেন যেখানে আমি এই পদ্ধতির বিষয়ে আরও পড়তে পারি।
রাহুল প্রসাদ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.