क्या मैं चेतावनी की कोशिश कर सकता / सकती हूं?


358

मुझे कुछ php मूल कार्यों से फेंके जा रहे कुछ चेतावनियों को पकड़ने और फिर उन्हें संभालने की आवश्यकता है।

विशेष रूप से:

array dns_get_record  ( string $hostname  [, int $type= DNS_ANY  [, array &$authns  [, array &$addtl  ]]] )

DNS क्वेरी विफल होने पर यह एक चेतावनी फेंकता है।

try/ catchकाम नहीं करता क्योंकि चेतावनी अपवाद नहीं है।

मेरे पास अब 2 विकल्प हैं:

  1. set_error_handler ओवरकिल की तरह लगता है क्योंकि मुझे पेज में हर चेतावनी को फ़िल्टर करने के लिए इसका इस्तेमाल करना है (क्या यह सच है?);

  2. त्रुटि रिपोर्टिंग / प्रदर्शन को समायोजित करें ताकि इन चेतावनियों को स्क्रीन पर प्रतिध्वनित न किया जाए, फिर रिटर्न मान जांचें; यदि यह false, होस्टनाम के लिए कोई रिकॉर्ड नहीं मिला है।

यहां सबसे अच्छा अभ्यास क्या है?


1
stackoverflow.com/questions/136899/… इस तरह की चीजों के बारे में एक अच्छी चर्चा है।
Mez

नीचे एक उत्तर था जो हटा दिया गया था? या तो मालिक द्वारा या किसी के द्वारा?
user121196

यह भी देखें: stackoverflow.com/questions/1087365
dreftymac

@ user121196: हाँ। मालिक द्वारा।
कक्षा

जवाबों:


373

त्रुटि हैंडलर को सेट और पुनर्स्थापित करें

एक संभावना यह है कि कॉल से पहले अपने स्वयं के त्रुटि हैंडलर को सेट करें और बाद में पिछली त्रुटि हैंडलर को पुनर्स्थापित करें restore_error_handler()

set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();

आप इस विचार पर निर्माण कर सकते हैं और एक पुन: प्रयोज्य त्रुटि हैंडलर लिख सकते हैं जो आपके लिए त्रुटियों को लॉग करता है।

set_error_handler([$logger, 'onSilencedError']);
dns_get_record();
restore_error_handler();

त्रुटियों को अपवादों में बदलना

आप सभी php त्रुटियों को अपवादों में बदलने के लिए set_error_handler()और ErrorExceptionवर्ग का उपयोग कर सकते हैं ।

set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
    // error was suppressed with the @-operator
    if (0 === error_reporting()) {
        return false;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

try {
    dns_get_record();
} catch (ErrorException $e) {
    // ...
}

अपने स्वयं के त्रुटि हैंडलर का उपयोग करते समय ध्यान देने योग्य बात यह है कि यह error_reportingसेटिंग को बायपास कर देगा और आपकी त्रुटि हैंडलर को सभी त्रुटियां (नोटिस, चेतावनियां, आदि) पास कर देगा। आप set_error_handler()किस त्रुटि प्रकार को प्राप्त करना चाहते हैं या ... = error_reporting()त्रुटि हैंडलर के अंदर का उपयोग करके वर्तमान सेटिंग को एक्सेस करने के लिए परिभाषित करने के लिए एक दूसरा तर्क सेट कर सकते हैं ।

चेतावनी को दबाना

एक अन्य संभावना @ ऑपरेटर के साथ कॉल को दबाने और dns_get_record()बाद में वापसी मूल्य की जांच करने की है। लेकिन मैं इसके खिलाफ सलाह दूंगा क्योंकि त्रुटियों / चेतावनियों को संभाला जाना चाहिए, दबाया नहीं जाना चाहिए।


3
क्या फंक्शन कॉल से ठीक पहले अपना खुद का एरर हैंडलर सेट करना उचित है, तब एरर_रॉलर_हैंडलर तब होता है जब एरर चेकिंग होती है?
user121196

2
क्या यह सुरक्षित होगा यदि कई समवर्ती अनुरोध हैं, और प्रत्येक अनुरोध 1.set_error_handler () करता है। २.डाइट 3.restore_error_handler?
user121196

4
धन्यवाद; इससे मदद मिलती है। (और वे कहते हैं कि PHP एक आपदा नहीं है।)
हारून मिलर

2
त्रुटियों को दबाने के लिए @ का उपयोग करने से बचने के लिए +1। E_WARNING वास्तव में एक गैर-घातक त्रुटि है। सामान्य तौर पर आपको हमेशा त्रुटियों को उचित रूप से संभालने की कोशिश करनी चाहिए। यदि आपके एप्लिकेशन को set_error_handler के उपयोग की आवश्यकता है, तो ऐसा करें। आमतौर पर त्रुटियों को लॉग करना और उन्हें उत्पादन वातावरण में प्रदर्शन को अक्षम करना उचित है। लॉग की जाँच करने पर आप देख सकते हैं कि आपके विकास के माहौल में कहाँ बदलाव करना है। बहुत सारे उदाहरण जहां मैंने @ fopen / @ को देखा है और पता नहीं क्यों डेवलपर ने त्रुटियों से बचने या set_error_handler का उपयोग करके त्रुटि को संभालने के लिए चेक नहीं किया।
फेरी २ f

5
चेतावनियों को अपवादों में बदलने के बारे में एक टिप्पणी: एक चेतावनी आपके ऐप को निरस्त नहीं करेगी- एक बिना अपवाद के अपवाद!
अल्वारो गोंजालेज

149

समाधान जो वास्तव में काम करता है E_WARNING, पैरामीटर के साथ सरल त्रुटि हैंडलर की स्थापना करता है , जैसे:

set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();

function warning_handler($errno, $errstr) { 
// do something
}

4
अनाम callableघोषणा के साथ स्ट्रिंग के बजाय यहाँ भी इस्तेमाल किया जा सकता है
vp_arth

धन्यवाद, लेकिन मैं महत्वपूर्ण ब्लॉक के बाद त्रुटि-हैंडलर को कैसे हटा सकता हूं?
येवगेनी अफानसेयेव

3
अति उत्कृष्ट! बस फंक्शन के trow new \Exception($errstr, $errno);अंदर warning_handler। धन्यवाद।
व्लादिमीर वुकानैक

यह यहाँ सबसे अच्छा जवाब है!
lewis4u

28

@ऑपरेटर के साथ सावधान रहें - जबकि यह चेतावनियों को दबाता है यह घातक त्रुटियों को भी दबाता है। मैंने एक प्रणाली में एक समस्या को डीबग करने में बहुत समय बिताया, जहां किसी ने लिखा था @mysql_query( '...' )और समस्या यह थी कि mysql समर्थन को PHP में लोड नहीं किया गया था और इसने एक मूक घातक त्रुटि फेंक दी थी। यह उन चीजों के लिए सुरक्षित होगा जो PHP कोर का हिस्सा हैं लेकिन कृपया इसका उपयोग सावधानी से करें।

bob@mypc:~$ php -a
Interactive shell

php > echo @something(); // this will just silently die...

कोई और अधिक उत्पादन - सौभाग्य यह डिबगिंग!

bob@mypc:~$ php -a
Interactive shell

php > echo something(); // lets try it again but don't suppress the error
PHP Fatal error:  Call to undefined function something() in php shell code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
bob@mypc:~$ 

इस बार हम देख सकते हैं कि यह असफल क्यों हुआ।


5

मैं एक चेतावनी को आज़माना / पकड़ना चाहता था, लेकिन साथ ही साथ सामान्य चेतावनी / त्रुटि लॉगिंग (जैसे /var/log/apache2/error.log) रखता हूँ ; जिसके लिए हैंडलर को वापस लौटना होगाfalse । हालांकि, "नया फेंक ..." बयान मूल रूप से निष्पादन को बाधित करता है, एक तो "रैप इन फंक्शन" ट्रिक करना है, इस पर भी चर्चा की:

क्या php में अपवाद को फेंकने का एक स्थिर तरीका है

या, संक्षेप में:

  function throwErrorException($errstr = null,$code = null, $errno = null, $errfile = null, $errline = null) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
  }
  function warning_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
    return false && throwErrorException($errstr, 0, $errno, $errfile, $errline);
    # error_log("AAA"); # will never run after throw
    /* Do execute PHP internal error handler */
    # return false; # will never run after throw
  }
  ...
  set_error_handler('warning_handler', E_WARNING);
  ...
  try {
    mkdir($path, 0777, true);
  } catch (Exception $e) {
    echo $e->getMessage();
    // ...
  }

संपादित करें: करीब निरीक्षण के बाद, यह पता चलता है कि यह काम नहीं करता है: " return false && throwErrorException ...", मूल रूप से, अपवाद को फेंकना नहीं है, और बस त्रुटि लॉग में लॉग इन करें; " false &&" भाग को, जैसा कि " " हटा दिया जाता है return throwErrorException ..., अपवाद फेंकने वाले कार्य को बना देगा, लेकिन फिर error_log में लॉग इन नहीं करेगा ... मैं अभी भी इसे पोस्ट करूंगा, हालांकि, जैसा कि मैंने इस व्यवहार को कहीं और नहीं देखा है।


4

आपको संभवतः पूरी तरह से चेतावनी से छुटकारा पाने की कोशिश करनी चाहिए, लेकिन अगर यह संभव नहीं है, तो आप @ (यानी @dns_get_record (...)) के साथ कॉल को प्रीपेन्ड कर सकते हैं और फिर किसी भी जानकारी का उपयोग कर सकते हैं जो आपको चेतावनी देने के लिए मिल सकती है। या नहीं।


4

सामान्य रूप से आपको कभी भी @ का उपयोग नहीं करना चाहिए जब तक कि यह एकमात्र समाधान न हो। उस विशिष्ट मामले में फ़ंक्शन dns_check_record का उपयोग यह जानने के लिए पहले किया जाना चाहिए कि क्या रिकॉर्ड मौजूद है।


3

file_get_contents()एक बाहरी url के लिए एक कॉल के आसपास कोड की इन पंक्तियों के संयोजन से मुझे चेतावनी को संभालने में मदद मिली जैसे " स्ट्रीम खोलने में विफल: कनेक्शन समय से बाहर " बहुत बेहतर:

set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
    throw new ErrorException( $err_msg, 0, $err_severity, $err_file, $err_line );
}, E_WARNING);
try {
    $iResult = file_get_contents($sUrl);
} catch (Exception $e) {
    $this->sErrorMsg = $e->getMessage();
}
restore_error_handler();

यह समाधान वस्तु संदर्भ के भीतर भी काम करता है। आप इसे किसी फ़ंक्शन में उपयोग कर सकते हैं:

public function myContentGetter($sUrl)
{
  ... code above ...
  return $iResult;
}

2

यदि dns_get_record()विफल हो जाता है, तो उसे वापस लौटना चाहिए FALSE, इसलिए आप चेतावनी को दबा सकते हैं @और फिर वापसी मूल्य की जांच कर सकते हैं।


0

यह जाँचने का प्रयास करें कि क्या यह कुछ बूलियन मान लौटाता है या नहीं, आप इसे शर्त के रूप में रख सकते हैं। मैंने oci_execute (...) के साथ इसका सामना किया, जो मेरी अनूठी कुंजियों के साथ कुछ उल्लंघन कर रहा था।

ex.
oci_parse($res, "[oracle pl/sql]");
if(oci_execute){
...do something
}

0

FolderStructure

index.php //Script File
logs //Folder for log Every warning and Errors
CustomException.php //Custom exception File

CustomException.php

/**
* Custom error handler
*/
function handleError($code, $description, $file = null, $line = null, $context = null) {
    $displayErrors = ini_get("display_errors");;
    $displayErrors = strtolower($displayErrors);
    if (error_reporting() === 0 || $displayErrors === "on") {
        return false;
    }
    list($error, $log) = mapErrorCode($code);
    $data = array(
        'timestamp' => date("Y-m-d H:i:s:u", time()),
        'level' => $log,
        'code' => $code,
        'type' => $error,
        'description' => $description,
        'file' => $file,
        'line' => $line,
        'context' => $context,
        'path' => $file,
        'message' => $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'
    );
    $data = array_map('htmlentities',$data);
    return fileLog(json_encode($data));
}

/**
* This method is used to write data in file
* @param mixed $logData
* @param string $fileName
* @return boolean
*/
function fileLog($logData, $fileName = ERROR_LOG_FILE) {
    $fh = fopen($fileName, 'a+');
    if (is_array($logData)) {
        $logData = print_r($logData, 1);
    }
    $status = fwrite($fh, $logData . "\n");
    fclose($fh);
//    $file = file_get_contents($filename);
//    $content = '[' . $file .']';
//    file_put_contents($content); 
    return ($status) ? true : false;
}

/**
* Map an error code into an Error word, and log location.
*
* @param int $code Error code to map
* @return array Array of error word, and log location.
*/
function mapErrorCode($code) {
    $error = $log = null;
    switch ($code) {
        case E_PARSE:
        case E_ERROR:
        case E_CORE_ERROR:
        case E_COMPILE_ERROR:
        case E_USER_ERROR:
            $error = 'Fatal Error';
            $log = LOG_ERR;
            break;
        case E_WARNING:
        case E_USER_WARNING:
        case E_COMPILE_WARNING:
        case E_RECOVERABLE_ERROR:
            $error = 'Warning';
            $log = LOG_WARNING;
            break;
        case E_NOTICE:
        case E_USER_NOTICE:
            $error = 'Notice';
            $log = LOG_NOTICE;
            break;
        case E_STRICT:
            $error = 'Strict';
            $log = LOG_NOTICE;
            break;
        case E_DEPRECATED:
        case E_USER_DEPRECATED:
            $error = 'Deprecated';
            $log = LOG_NOTICE;
            break;
        default :
            break;
    }
    return array($error, $log);
}
//calling custom error handler
set_error_handler("handleError");

बस इस तरह से अपनी स्क्रिप्ट फ़ाइल में फ़ाइल के ऊपर शामिल करें

index.php

error_reporting(E_ALL);
ini_set('display_errors', 'off');
define('ERROR_LOG_FILE', 'logs/app_errors.log');

include_once 'CustomException.php';
echo $a; // here undefined variable warning will be logged into logs/app_errors.log

-2

मैं केवल चेतावनी का उपयोग करने के लिए @ का उपयोग करने की सलाह दूंगा जब यह एक सीधे आगे का ऑपरेशन है (जैसे $ प्रोप = @ ($ उच्च / ($ चौड़ाई - $ गहराई)), शून्य चेतावनी द्वारा विभाजन को छोड़ने के लिए)। हालाँकि ज्यादातर मामलों में इसे संभालना बेहतर होता है।


2
यह एक समय है जब आप निश्चित रूप से @ का उपयोग नहीं करना चाहते हैं - आपके पास ऑपरेशन पर नियंत्रण है और यह जांच कर सकता है कि क्या यह शून्य से विभाजन है या इसे करने से पहले नहीं।
इबोरोब
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.