2010-06-18 24 views
24

Tôi có một biểu thức toán học lớn phải được tạo động. Ví dụ: khi tôi đã phân tích cú pháp "cái gì đó", kết quả sẽ là một chuỗi như sau: "$foo+$bar/$baz";.PHP, Làm thế nào để bắt một bộ phận bằng không?

Vì vậy, để tính kết quả của biểu thức mà tôi đang sử dụng các chức năng eval ... một cái gì đó như thế này:

eval("\$result = $expresion;"); 
echo "The result is: $result"; 

Vấn đề ở đây là đôi khi tôi nhận được lỗi nói rằng đã có một bộ phận của không, và tôi không biết cách bắt ngoại lệ đó. Tôi đã thử những thứ như:

eval("try{\$result = $expresion;}catch(Exception \$e){\$result = 0;}"); 
echo "The result is: $result"; 

Hoặc:

try{ 
    eval("\$result = $expresion;"); 
} 
catch(Exception $e){ 
    $result = 0; 
} 
echo "The result is: $result"; 

Nhưng nó không hoạt động. Vì vậy, làm thế nào tôi có thể tránh được rằng ứng dụng của tôi bị treo khi có một bộ phận bằng không?

Edit:

Trước tiên, tôi muốn làm rõ điều gì đó: biểu thức được xây dựng tự động, vì vậy tôi không thể chỉ eval nếu mẫu số là zero. Vì vậy ... liên quan đến nhận xét của Mark Baker, hãy để tôi cho bạn một ví dụ. phân tích cú pháp của tôi có thể xây dựng một cái gì đó như thế này:

"$foo + $bar * ($baz/($foz - $bak))" 

Các phân tích cú pháp xây dựng các bước chuỗi bước mà không lo lắng về giá trị của các vars ... do đó, trong trường hợp này nếu $foz == $bak có trong thực tế, một phép chia cho không: $baz/(0).

Mặt khác như Pete đề nghị, tôi đã cố gắng:

<?php 
$a = 5; 
$b = 0; 

if(@eval(" try{ \$res = $a/$b; } catch(Exception \$e){}") === FALSE) 
     $res = 0; 
echo "$res\n"; 
?> 

Nhưng nó không in bất cứ điều gì.

+1

bạn có thể kiểm tra nếu '$ expression' được chia cho zero trước? –

+0

@Anthony Forloney: Câu hỏi hay, câu trả lời của tôi giả định bạn có thể, nhưng nếu Cristian thực sự đang sử dụng eval cho điều này, thì câu trả lời có lẽ là "không". – Powerlord

+2

Sử dụng 'eval' có thể là một ý tưởng tồi. Bây giờ bạn sẽ cho phép người dùng cuối của bạn thực thi mã PHP trên máy chủ của bạn.Tôi không biết một giải pháp thay thế, vì vậy tôi không đăng câu trả lời, nhưng bạn nên suy nghĩ xem liệu bạn có muốn tôi có thể nhập vào bất kỳ mã PHP nào bất kể việc phá hoại trang web của bạn như thế nào. – Umang

Trả lời

15
if ($baz == 0.0) { 
    echo 'Divisor is 0'; 
} else { 
    ... 
} 

Thay vì eval sử dụng, đó là rất nguy hiểm nếu bạn đang sử dụng với người sử dụng đầu vào trong biểu evalled, tại sao không sử dụng một phân tích cú pháp thích hợp như evalmath on PHPClasses, và điều này làm tăng một ngoại lệ sạch trên chia cho số không

+0

Không ... như tôi đã nói biểu thức được xây dựng theo kiểu thực tế. Nếu đó là một biểu hiện tĩnh thì nó sẽ rất dễ, nhưng không phải vậy. – Cristian

+4

Làm thế nào nó được xây dựng động? Nó phải được "xây dựng" bằng cách nào đó bởi "trình phân tích cú pháp" của bạn ... và tại thời điểm đó bạn sẽ có thể xác định xem số chia là 0 hay không! –

+0

Điều này sẽ hoạt động nếu bạn thay thế $ baz bằng eval ("\ $ result = $ baz;") và sau đó kiểm tra là $ result là 0 hay không. – vad

2
if(@eval("\$result = $expresion;")===FALSE){ 
    $result=0; 
} 

Sẽ không chỉ bị chia cho 0 lỗi.

+0

+1, nhưng thay vì * $ result = 0; * sử dụng * $ result = "#error"; * hoặc ném ngoại lệ. – ern0

+0

eval là ác! Vui lòng KHÔNG sử dụng –

6

Đây là một giải pháp:

<?php 

function e($errno, $errstr, $errfile, $errline) { 
    print "caught!\n"; 
} 

set_error_handler('e'); 

eval('echo 1/0;'); 

Xem set_error_handler()

+0

"Không thể bắt lỗi phân tích cú pháp trong eval() bằng cách sử dụng set_error_handler()" http://www.php.net/manual/en/function.eval.php – Pete

+4

@Pete: Right , nhưng OP đã hỏi về phân chia bằng 0 lỗi, không phân tích lỗi. Tôi đã thử nghiệm kịch bản trên và nó bắt lỗi. –

0

Sử dụng một @ này cho php không cảnh báo đầu ra trong trường hợp lỗi (An error control operator.).

eval("\$result = @($expresion);"); 
if ($result == 0) { 
    // do division by zero handling 
} else { 
    // it's all good 
} 
+0

Không tốt. Nếu '$ expression =" 0/5 "' thì sao? Sau đó, bạn có một dương tính giả. –

+0

Phân chia theo số không thực sự trả về 'false', không phải 0. Hãy thử' $ result === false' để thay thế. – Hubro

3

Như những người khác đã đề cập, xem xét thử một giải pháp mà sẽ cho phép bạn kiểm tra nếu mẫu số là 0.

Kể từ khi lời khuyên mà dường như vô dụng mục đích của bạn, đây là một nền chút về xử lý lỗi PHP.

Phiên bản đầu tiên của PHP không có ngoại lệ. Thay vào đó, thông báo lỗi của các cấp độ khác nhau được nâng lên (Thông báo, Cảnh báo, Vv). Lỗi nghiêm trọng sẽ ngừng thực thi.

PHP5 đưa ngoại lệ vào bảng và các thư viện được cung cấp PHP mới hơn (PDO) sẽ ném ngoại lệ khi những điều xấu/không mong muốn xảy ra. Hoever, codebase lõi KHÔNG được viết lại để sử dụng ngoại lệ. Các chức năng và hoạt động cốt lõi vẫn dựa vào hệ thống lỗi cũ.

Khi bạn chia cho 0, bạn nhận được một cảnh báo, không phải là một ngoại lệ

PHP Warning: Division by zero in /foo/baz/bar/test.php(2) : eval()'d code on line 1 
PHP Stack trace: 
PHP 1. {main}() /foo/baz/bar/test.php:0 
PHP 2. eval() /foo/baz/bar/test.php:2 

Nếu bạn muốn "bắt" này, bạn sẽ cần phải set a custom error handler rằng sẽ phát hiện phép chia cho không lỗi và làm điều gì đó về họ. Thật không may, trình xử lý lỗi tùy chỉnh là bắt tất cả, có nghĩa là bạn cũng cần phải viết một số mã để làm điều gì đó phù hợp với tất cả các lỗi khác.

+0

Tôi đang gặp phải Lỗi nghiêm trọng với PHP 5.6. Không phải là cảnh báo. – MightyPork

+0

nevermind nó đã được Framework của tôi làm một số điều thực sự chậm phát triển với set_error_handler() – MightyPork

2

Tôi cũng đang đối mặt với vấn đề đó (biểu thức động). Nhạy cảm nó theo cách đó có thể không phải là cách đẹp nhất nhưng nó hoạt động. Thay vì ném một ngoại lệ, tất nhiên bạn có thể trả về null hoặc false hoặc bất cứ điều gì bạn muốn. Hi vọng điêu nay co ich.

function eval_expression($expression) 
{ 
    ob_start(); 
    eval('echo (' . $expression . ');'); 
    $result = ob_get_contents(); 
    ob_end_clean(); 
    if (strpos($result, 'Warning: Division by zero')!==false) 
    { 
     throw new Exception('Division by zero'); 
    } 
    else return (float)$result; 
} 
0

Một chuỗi chứa số và toán tử + - */được chuyển làm đầu vào. Chương trình phải đánh giá giá trị của biểu thức (theo BODMAS) và in đầu ra.

Ví dụ đầu vào/đầu ra: Nếu đối số là "7 + 4 * 5", đầu ra phải là 27. Nếu đối số là "55 + 21 * 11 - 6/0", đầu ra phải là "lỗi" (Khi phân chia bằng 0 không được xác định).

3

Bạn chỉ cần thiết lập một xử lý lỗi để ném một ngoại lệ trong trường hợp lỗi:

set_error_handler(function() { 
    throw new Exception('Ach!'); 
}); 

try { 
    $result = 4/0; 
} catch(Exception $e){ 
    echo "Divide by zero, I don't fear you!".PHP_EOL; 
    $result = 0; 
} 

restore_error_handler(); 
0

Vấn đề:

b=1; c=0; a=b/c; // Error Divide by zero

Giải pháp đơn giản:

if(c!=0) a=b/c; 
else // error handling 
0

tôi cũng đã đấu tranh với điều này, các giải pháp set_error_handler không hoạt động đối với tôi, có lẽ dựa trên sự khác biệt phiên bản PHP.

Các giải pháp đối với tôi là cố gắng để phát hiện một lỗi trên shutdown:

// Since set_error_handler doesn't catch Fatal errors, we do this 
function shutdown() 
{ 
    $lastError = error_get_last(); 
    if (!empty($lastError)) { 
     $GLOBALS['logger']->debug(null, $lastError); 
    } 
} 
register_shutdown_function('shutdown'); 

Tôi không chắc chắn lý do tại sao một chia cho 0 là tắt chứ không phải được xử lý bởi các set_error_handler nhưng điều này đã giúp tôi có được vượt ra ngoài nó chỉ lặng lẽ chết.

1

On PHP7 bạn có thể sử dụng DivisionByZeroError

try { 
    echo 1/0; 
} 
catch(DivisionByZeroError $e){ 
    echo "got $e"; 
} 
Các vấn đề liên quan