Tôi có thể thử / bắt cảnh báo không?


358

Tôi cần phải bắt một số cảnh báo bị ném từ một số hàm riêng của php và sau đó xử lý chúng.

Đặc biệt:

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

Nó đưa ra một cảnh báo khi truy vấn DNS không thành công.

try/ catchkhông hoạt động vì cảnh báo không phải là ngoại lệ.

Bây giờ tôi có 2 lựa chọn:

  1. set_error_handler có vẻ như quá mức cần thiết bởi vì tôi phải sử dụng nó để lọc mọi cảnh báo trong trang (điều này có đúng không?);

  2. Điều chỉnh báo cáo / hiển thị lỗi để những cảnh báo này không bị lặp lại trên màn hình, sau đó kiểm tra giá trị trả về; nếu nó false, không có hồ sơ được tìm thấy cho tên máy chủ.

Thực hành tốt nhất ở đây là gì?


1
stackoverflow.com/questions/136899/ cấp là một cuộc thảo luận tốt về những thứ như thế này.
Mez

Có một câu trả lời dưới đây đã bị xóa? hoặc bởi chủ sở hữu hoặc bởi ai đó?
dùng121196


@ user121196: Có. Do chủ sở hữu.
Các cuộc đua nhẹ nhàng trong quỹ đạo

Câu trả lời:


373

Đặt và khôi phục trình xử lý lỗi

Một khả năng là đặt trình xử lý lỗi của riêng bạn trước cuộc gọi và khôi phục trình xử lý lỗi trước đó sau restore_error_handler().

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

Bạn có thể xây dựng trên ý tưởng này và viết một trình xử lý lỗi có thể sử dụng lại để ghi lại các lỗi cho bạn.

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

Biến lỗi thành ngoại lệ

Bạn có thể sử dụng set_error_handler()ErrorExceptionlớp để biến tất cả các lỗi php thành ngoại lệ.

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) {
    // ...
}

Điều quan trọng cần lưu ý khi sử dụng trình xử lý lỗi của riêng bạn là nó sẽ bỏ qua error_reportingcài đặt và chuyển tất cả các lỗi (thông báo, cảnh báo, v.v.) cho trình xử lý lỗi của bạn. Bạn có thể đặt đối số thứ hai set_error_handler()để xác định loại lỗi bạn muốn nhận hoặc truy cập cài đặt hiện tại bằng cách sử dụng... = error_reporting() bên trong trình xử lý lỗi.

Ức chế cảnh báo

Một khả năng khác là chặn cuộc gọi với toán tử @ và kiểm tra giá trị trả về dns_get_record()sau đó. Nhưng tôi khuyên bạn nên chống lại điều này vì các lỗi / cảnh báo được kích hoạt để được xử lý, không được loại bỏ.


3
Có nên đặt trình xử lý lỗi của riêng tôi ngay trước khi gọi hàm, sau đó restore_error_handler khi kiểm tra lỗi được thực hiện không?
dùng121196

2
đây sẽ là luồng an toàn nếu có nhiều yêu cầu đồng thời và mỗi yêu cầu thực hiện 1.set_error_handler (). 2.doit 3.restore_error_handler?
dùng121196

4
Cảm ơn; điều này có ích. (Và họ nói PHP không phải là thảm họa.)
Aaron Miller

2
+1 để tránh sử dụng @ để loại bỏ lỗi. E_WARNING thực sự là một lỗi không nghiêm trọng. Nói chung, bạn nên luôn luôn cố gắng xử lý lỗi một cách thích hợp. Nếu ứng dụng của bạn yêu cầu sử dụng set_error_handler thì hãy làm như vậy. Thông thường nên ghi nhật ký lỗi và vô hiệu hóa hiển thị chúng trong môi trường sản xuất. Khi kiểm tra nhật ký, bạn có thể thấy nơi cần thay đổi trong môi trường phát triển của mình. Quá nhiều trường hợp tôi đã thấy @ fopen / @ hủy liên kết và tự hỏi tại sao nhà phát triển không thực hiện kiểm tra để tránh lỗi hoặc xử lý lỗi bằng set_error_handler.
fyrye

5
Một lưu ý về việc biến cảnh báo thành ngoại lệ: cảnh báo sẽ không hủy bỏ ứng dụng của bạn. còn tự do ngoại lệ sẽ làm!
Álvaro González

149

Giải pháp thực sự hoạt động hóa ra là thiết lập trình xử lý lỗi đơn giản với E_WARNINGtham số, như vậy:

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

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

4
cũng callablecó thể sử dụng ẩn danh ở đây thay vì chuỗi với khai báo hàm
vp_arth 11/215

Cảm ơn, nhưng làm cách nào tôi có thể xóa trình xử lý lỗi sau khối quan trọng?
Yevgeniy Afanasyev

3
Thông minh! Chỉ trow new \Exception($errstr, $errno);bên trong warning_handlerchức năng. Cảm ơn.
Vladimir Vukanac

Đây là câu trả lời tốt nhất ở đây!
lewis4u

28

Hãy cẩn thận với người @vận hành - trong khi nó ngăn chặn các cảnh báo, nó cũng ngăn chặn các lỗi nghiêm trọng. Tôi đã dành rất nhiều thời gian để gỡ lỗi một vấn đề trong một hệ thống mà ai đó đã viết @mysql_query( '...' )và vấn đề là sự hỗ trợ của mysql không được tải vào PHP và nó đã gây ra một lỗi nghiêm trọng thầm lặng. Nó sẽ an toàn cho những thứ là một phần của lõi PHP nhưng vui lòng sử dụng nó một cách cẩn thận.

bob@mypc:~$ php -a
Interactive shell

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

Không có đầu ra nữa - chúc may mắn gỡ lỗi này!

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:~$ 

Lần này chúng ta có thể thấy tại sao nó thất bại.


5

Tôi muốn thử / bắt một cảnh báo, nhưng đồng thời vẫn giữ cảnh báo / ghi nhật ký lỗi thông thường (ví dụ: trong /var/log/apache2/error.log); mà người xử lý phải trả lại false. Tuy nhiên, vì câu lệnh "throw new ..." về cơ bản làm gián đoạn quá trình thực thi, nên người ta phải thực hiện thủ thuật "bọc trong chức năng", cũng được thảo luận trong:

Có một cách tĩnh để ném ngoại lệ trong php

Hoặc, ngắn gọn:

  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();
    // ...
  }

EDIT: sau khi kiểm tra kỹ hơn, hóa ra nó không hoạt động: return false && throwErrorException ...về cơ bản, " " sẽ không ném ngoại lệ và chỉ đăng nhập vào nhật ký lỗi; xóa phần " false &&", như trong " return throwErrorException ...", sẽ khiến ngoại lệ ném hoạt động, nhưng sau đó sẽ không đăng nhập error_log ... Tuy nhiên, tôi vẫn giữ thông báo này được đăng ở nơi khác.


4

Có lẽ bạn nên cố gắng loại bỏ hoàn toàn cảnh báo, nhưng nếu không thể, bạn có thể thực hiện lại cuộc gọi bằng @ (tức là @dns_get_record (...)) và sau đó sử dụng bất kỳ thông tin nào bạn có thể nhận ra nếu cảnh báo xảy ra hay không.


4

Normaly bạn không bao giờ nên sử dụng @ trừ khi đây là giải pháp duy nhất. Trong trường hợp cụ thể đó, hàm dns_check_record nên được sử dụng trước tiên để biết bản ghi có tồn tại hay không.


3

Kết hợp các dòng mã này xung quanh một file_get_contents()cuộc gọi đến một url bên ngoài đã giúp tôi xử lý các cảnh báo như " không thể mở luồng: Kết nối đã hết thời gian " tốt hơn nhiều:

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();

Giải pháp này hoạt động trong bối cảnh đối tượng, quá. Bạn có thể sử dụng nó trong một chức năng:

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

2

Nếu dns_get_record()thất bại, nó sẽ trả về FALSE, vì vậy bạn có thể chặn cảnh báo bằng @và sau đó kiểm tra giá trị trả về.


0

hãy thử kiểm tra xem nó có trả về một số giá trị boolean hay không, sau đó bạn có thể chỉ cần đặt nó làm điều kiện. Tôi đã gặp điều này với oci_execute (...) đang trả lại một số vi phạm với các khóa duy nhất của tôi.

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

0

Thư mục Cấu trúc

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");

chỉ bao gồm tập tin ở trên vào tập tin kịch bản của bạn như thế này

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

Tôi chỉ khuyên bạn nên sử dụng @ để chặn các cảnh báo khi đó là thao tác chuyển tiếp thẳng (ví dụ: $ prop = @ ($ high / ($ width - $ sâu)); bỏ qua phân chia bằng các cảnh báo bằng 0). Tuy nhiên, trong hầu hết các trường hợp, tốt hơn là xử lý.


2
Đây là một lần bạn chắc chắn không muốn sử dụng @ - bạn có quyền kiểm soát hoạt động và có thể kiểm tra xem đó có phải là phép chia cho số 0 hay không trước khi thực hiện.
Eborbob
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.