পিএইচপি-র যাদু পদ্ধতির প্রসঙ্গে `ট্রিগার_েরর` বনাম` থ্রো ব্যতিক্রম


13

যাদু পদ্ধতিরtrigger_error প্রসঙ্গে সঠিক ব্যবহার (যদি থাকে তবে) নিয়ে আমি একজন সহকর্মীর সাথে বিতর্ক করছি । প্রথমত, আমি মনে করি যে এটিকে একটি মামলা বাদ দিয়ে এড়ানো উচিত ।trigger_error

বলুন আমাদের একটি পদ্ধতি সহ একটি ক্লাস রয়েছে foo()

class A {
    public function foo() {
        echo 'bar';
    }
}

এখন বলুন আমরা ঠিক একই ইন্টারফেসটি সরবরাহ করতে চাই তবে সমস্ত পদ্ধতি কলগুলি ধরতে একটি যাদু পদ্ধতি ব্যবহার করি

class B {
    public function __call($method, $args) {
        switch (strtolower($method)) {
        case 'foo':
            echo 'bar';
            break;
        }
    }
}

$a = new A;
$b = new B;

$a->foo(); //bar
$b->foo(); //bar

উভয় শ্রেণিই তারা যেভাবে সাড়া দেয় সেভাবে একই foo()তবে একটি অবৈধ পদ্ধতিতে কল করার সময় পৃথক।

$a->doesntexist(); //Error
$b->doesntexist(); //Does nothing

আমার যুক্তিটি হল যে trigger_errorকোনও অজানা পদ্ধতি ধরা পড়লে যাদু পদ্ধতিগুলি কল করা উচিত

class B {
    public function __call($method, $args) {
        switch (strtolower($method)) {
        case 'foo':
            echo 'bar';
            break;
        default:
            $class = get_class($this);
            $trace = debug_backtrace();
            $file = $trace[0]['file'];
            $line = $trace[0]['line'];
            trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
            break;
        }
    }
}

যাতে উভয় শ্রেণিই (প্রায়) একইরকম আচরণ করে

$a->badMethod(); //Call to undefined method A::badMethod() in [..] on line 28
$b->badMethod(); //Call to undefined method B::badMethod() in [..] on line 32

আমার ব্যবহারের ক্ষেত্রে একটি অ্যাক্টিভেকর্ড বাস্তবায়ন। আমি __callসেই পদ্ধতিগুলি ধরতে ও পরিচালনা করতে ব্যবহার করি যা মূলত একই জিনিসটি করে তবে সংশোধক যেমন Distinctবা Ignore, যেমন

selectDistinct()
selectDistinctColumn($column, ..)
selectAll()
selectOne()
select()

অথবা

insert()
replace()
insertIgnore()
replaceIgnore()

মত পদ্ধতি where(), from(), groupBy(), ইত্যাদি হার্ড কোডেড হয়।

আপনি দুর্ঘটনাক্রমে কল করলে আমার যুক্তি হাইলাইট হয় insret()। আমার সক্রিয় রেকর্ড বাস্তবায়ন যদি সমস্ত পদ্ধতির হার্ডকোড করে থাকে তবে এটি ত্রুটি হবে।

যে কোনও ভাল বিমূর্ততা হিসাবে, ব্যবহারকারীর প্রয়োগের বিবরণ সম্পর্কে অবহিত হওয়া উচিত এবং সম্পূর্ণ ইন্টারফেসের উপর নির্ভর করা উচিত। যাদু পদ্ধতি ব্যবহার করে এমন বাস্তবায়ন কেন অন্যরকম আচরণ করবে? উভয় একটি ত্রুটি হওয়া উচিত।

উত্তর:


7

একই ActiveRecord ইন্টারফেসের দুই বাস্তবায়নের নিন ( select(), where()ইত্যাদি)

class ActiveRecord1 {
    //Hardcodes all methods
}

class ActiveRecord2 {
    //Uses __call to handle some methods, hardcodes the rest
}

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

পিএইচপি-তে ফিরে যান - উভয় শ্রেণি যদি একই ইন্টারফেস প্রয়োগ করে তবে কেন তাদের একই আচরণ প্রদর্শিত হবে না?

যদি __callবা __callStaticকোনও অবৈধ পদ্ধতি সনাক্ত করে তবে তাদের ভাষার ডিফল্ট আচরণ নকল করতে একটি ত্রুটি ট্রিগার করা উচিত

$class = get_class($this);
$trace = debug_backtrace();
$file = $trace[0]['file'];
$line = $trace[0]['line'];
trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);

ব্যতিক্রম ব্যতীত ত্রুটিগুলি ব্যবহার করা উচিত কিনা সে বিষয়ে আমি তর্ক করছি না (তাদের 100% হওয়া উচিত নয়) তবে আমি বিশ্বাস করি যে পিএইচপি-র যাদু পদ্ধতিগুলি একটি ব্যতিক্রম - পাং উদ্দেশ্যে :) - ভাষাটির প্রসঙ্গে এই নিয়মের কাছে


1
দুঃখিত, তবে আমি এটি কিনিনি। এক দশক আগে যখন পিএইচপি-তে ক্লাস প্রথম প্রয়োগ করা হয়েছিল তখন কেন আমাদের ভেড়া হতে হবে 4.something?
ম্যাথু শার্লে

ধারাবাহিকতার জন্য ম্যাথুজ আমি ব্যতিক্রম বনাম ত্রুটিগুলি নিয়ে বিতর্ক করছি না (তর্ক নেই) বা পিএইচপি ডিজাইনের ব্যর্থতা আছে কিনা (তা করে), আমি যুক্তি দিচ্ছি যে এই অনন্য পরিস্থিতিতে, ধারাবাহিকতার জন্য , ভাষার আচরণ অনুকরণ করা ভাল
খ্রিস্টো

ধারাবাহিকতা সবসময় একটি ভাল জিনিস হয় না। একটি সামঞ্জস্যপূর্ণ কিন্তু দুর্বল নকশা এখনও একটি দুর্বল নকশা যা দিনের শেষে ব্যবহার করতে ব্যথা হয়।
ম্যাথু শার্লে

@ ম্যাথিউ সত্য, তবে আইএমও একটি অবৈধ পদ্ধতিতে কলটিতে ত্রুটিটি ট্রিগার করছে না 1) অনেকগুলি (সর্বাধিক?) ভাষা এর অন্তর্নির্মিত আছে, এবং 2) আপনি যে কোনও ক্ষেত্রে চান এমন কোনও ক্ষেত্রে আমি ভাবতে পারি না থেকে ধরা একটি অবৈধ পদ্ধতি কল এবং এটি পরিচালনা?
ক্রিসো

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

3

আমি আমার মতামত মতামত সেখানে ফেলে দিতে যাচ্ছি, কিন্তু আপনি যদি trigger_errorকোথাও ব্যবহার করেন , তবে আপনি কিছু ভুল করছেন। ব্যতিক্রমগুলি যাওয়ার উপায়।

ব্যতিক্রমগুলির সুবিধা:

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

আপনার উদ্বেগের সমাধান, এমন একটি পদ্ধতিতে কল করা যা বিদ্যমান নেই যা একটি বৈধ সম্ভাবনা হতে পারে । এটি সম্পূর্ণরূপে আপনি যে কোডটি লিখছেন তার প্রসঙ্গে নির্ভর করে তবে কিছু ঘটনা রয়েছে যেখানে এটি ঘটতে পারে। আপনার সঠিক ব্যবহারের ক্ষেত্রে সম্বোধন করে, কিছু ডাটাবেস সার্ভারগুলি এমন কিছু কার্যকারিতা মঞ্জুর করতে পারে যা অন্যরা তা করে না। ব্যবহার try/ catchএবং ব্যতিক্রম __call()একটি ফাংশন বনাম ক্ষমতা চেক করতে একটি ভিন্ন যুক্তি পুরাপুরি হয়।

ব্যবহারের জন্য আমি কেবলমাত্র ব্যবহারের ক্ষেত্রেই ভাবতে পারি trigger_errorতার জন্য E_USER_WARNINGবা তার চেয়ে কম। E_USER_ERRORযদিও ট্রিগার করা আমার মতে সর্বদা ত্রুটি।


প্রতিক্রিয়াটির জন্য ধন্যবাদ :) - 1) আমি সম্মত হই যে ব্যতিক্রমগুলি প্রায়শই ত্রুটির উপরে ব্যবহার করা উচিত - আপনার সমস্ত যুক্তি বৈধ পয়েন্ট। তবে .. আমি মনে করি যে এই প্রসঙ্গে আপনার যুক্তি ব্যর্থ হয় ..
খ্রিস্টো

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

আপনি যদি আমার দ্বিতীয় সম্পাদনাটি পড়েন তবে আপনি আমার ব্যবহারের ক্ষেত্রে দেখতে পাবেন। বলুন আপনার কাছে একই বর্গের দুটি বাস্তবায়ন রয়েছে, একটি __call এবং একটি হার্ডকোডযুক্ত পদ্ধতি সহ। প্রয়োগের বিশদটি উপেক্ষা করে, যখন উভয় শ্রেণি একই ইন্টারফেসটি বাস্তবায়ন করে তখন তাদের সাথে আলাদা আচরণ করা উচিত কেন? আপনি যদি ক্লাসটির সাথে হার্ডকডযুক্ত পদ্ধতিগুলি সহ একটি অবৈধ পদ্ধতি কল করেন তবে পিএইচপি একটি ত্রুটি ট্রিগার করবে । ব্যবহার trigger_error__call বা __callStatic নকল ভাষার ডিফল্ট আচরণ প্রেক্ষাপটে
chriso

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

@ ক্রিসো আমি বিশ্বাস করতে চাই যে কোর এখনও ত্রুটিগুলি ব্যবহার করে কারণ পিছনের সামঞ্জস্যের জন্য। আশা করি পিএইচপি 6 হ'ল পিএইচপি 5 এর মতো আরও একটি লিপ ফরোয়ার্ড এবং পুরোপুরি ত্রুটিগুলি ড্রপ করবে। দিনের শেষে, ত্রুটি এবং ব্যতিক্রম উভয়ই একই ফলাফল উত্পন্ন করে: কার্যকর করার কোডের তাত্ক্ষণিক সমাপ্তি। ব্যতিক্রম সহ আপনি কেন এবং কোথায় এত সহজ যদিও নির্ণয় করতে পারেন।
ম্যাথু শার্লে

3

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

function errorToExceptionHandler($errNo, $errStr, $errFile, $errLine, $errContext)
{
if (error_reporting() == 0) return;
throw new ErrorException($errStr, 0, $errNo, $errFile, $errLine);
}
set_error_handler('errorToExceptionHandler');

এটি ব্যবহার করে, এই প্রশ্নটি মোটা হয়ে যায়। অন্তর্নির্মিত ত্রুটিগুলি এখন ব্যতিক্রমগুলি উত্থাপন করে এবং তাই আপনার নিজের কোডটিও উচিত।


1
আপনি যদি এটি ব্যবহার করেন তবে আপনার ত্রুটির ধরণের পরীক্ষা করা দরকার, পাছে আপনি E_NOTICEব্যাতিক্রম হিসাবে রূপান্তরিত করবেন। এটা খারাপ হবে।
ম্যাথু শার্লে

1
না, E_NOTICES কে ব্যতিক্রমে রূপান্তর করা ভাল! সমস্ত নোটিশ ত্রুটি হিসাবে বিবেচনা করা উচিত; আপনি এগুলিকে ব্যতিক্রমে রূপান্তর করছেন কিনা তা ভাল অনুশীলন।
ওয়েন

2
সাধারণত আমি আপনার সাথে একমত হই, তবে দ্বিতীয়বার আপনি কোনও তৃতীয় পক্ষের কোড ব্যবহার শুরু করেন, এটি দ্রুত তার মুখের দিকে ঝুঁকে যায়।
ম্যাথু শার্লে

প্রায় সমস্ত তৃতীয় পক্ষের গ্রন্থাগারগুলি E_STRICT | E_ALL নিরাপদ। যদি আমি এমন কোড ব্যবহার করি যা না হয় তবে আমি andুকে ঠিক করে দেব। আমি ইস্যু ছাড়াই বছরের পর বছর ধরে এভাবে কাজ করেছি ।
ওয়েইন

আপনি সম্ভবত দ্বৈত আগে ব্যবহার করেন নি। মূলটি এর মতো সত্যই দুর্দান্ত তবে অনেকগুলি, অনেক তৃতীয় পক্ষের মডিউলগুলি নেই
ম্যাথু শার্লি

0

আইএমও, এটির জন্য এটি একটি কার্যকর বৈধ কেস trigger_error:

function handleError($errno, $errstring, $errfile, $errline, $errcontext) {
    if (error_reporting() & $errno) {
        // only process when included in error_reporting
        return handleException(new \Exception($errstring, $errno));
    }
    return true;
}

function handleException($exception){
    // Here, you do whatever you want with the generated
    // exceptions. You can store them in a file or database,
    // output them in a debug section of your page or do
    // pretty much anything else with it, as if it's a
    // normal variable

    switch ($code) {
        case E_ERROR:
        case E_CORE_ERROR:
        case E_USER_ERROR:
            // Make sure script exits here
            exit(1);
        default:
            // Let script continue
            return true;
    }
}

// Set error handler to your custom handler
set_error_handler('handleError');
// Set exception handler to your custom handler
set_exception_handler('handleException');


// ---------------------------------- //

// Generate warning
trigger_error('This went wrong, but we can continue', E_USER_WARNING);

// Generate fatal error :
trigger_error('This went horrible wrong', E_USER_ERROR);

এই কৌশলটি ব্যবহার করে, আপনি $errcontextযদি $exception->getTrace()ফাংশনটির মধ্যে করেন তবে আপনি প্যারামিটারটি পাবেন handleException। এটি নির্দিষ্ট ডিবাগিং উদ্দেশ্যে খুব কার্যকর।

দুর্ভাগ্যক্রমে, এটি কেবল তখনই কাজ করে যদি আপনি trigger_errorসরাসরি আপনার প্রসঙ্গ থেকে ব্যবহার করেন , যার অর্থ আপনি ফাংশনটি উলামা করার জন্য একটি মোড়ক ফাংশন / পদ্ধতি ব্যবহার করতে পারবেন না trigger_error(যাতে আপনি function debug($code, $message) { return trigger_error($message, $code); }নিজের সন্ধানের প্রসঙ্গে ডেটা চাইলে এমন কিছু করতে পারবেন না )।

আমি আরও ভাল বিকল্পের সন্ধান করছিলাম, তবে এখনও পর্যন্ত আমি কোনও খুঁজে পাইনি।

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