ฉันจะตรวจจับ“ ข้อผิดพลาดร้ายแรงที่จับได้” ในคำใบ้ประเภท PHP ได้อย่างไร


96

ฉันกำลังพยายามใช้ Type Hinting ของ PHP5 กับหนึ่งในคลาสของฉัน

class ClassA {
    public function method_a (ClassB $b)
    {}
}

class ClassB {}
class ClassWrong{}

การใช้งานที่ถูกต้อง:

$a = new ClassA;
$a->method_a(new ClassB);

ข้อผิดพลาดในการผลิต:

$a = new ClassA;
$a->method_a(new ClassWrong);

ข้อผิดพลาดร้ายแรงที่ตรวจจับได้: อาร์กิวเมนต์ 1 ที่ส่งไปยัง ClassA :: method_a () ต้องเป็นอินสแตนซ์ของ ClassB อินสแตนซ์ของ ClassWrong ที่กำหนด ...

เป็นไปได้ไหมที่จะจับข้อผิดพลาดนั้น (เนื่องจากมีข้อความว่า "catchable") และถ้าใช่อย่างไร?


4
สำหรับการอ้างอิงในอนาคต: ข้อยกเว้นในเครื่องยนต์ (สำหรับ PHP 7) - การเริ่มต้นด้วย PHP 7 อาจเกิดข้อผิดพลาดร้ายแรงได้ นอกจากนี้ยังมีไว้สำหรับ"ข้อผิดพลาดร้ายแรงที่จับได้" ( E_RECOVERABLE_ERROR) ซึ่งถูกจับโดยเริ่มต้นด้วย PHP 7 ..
hakre

คำตอบ:


114

อัปเดต: นี่ไม่ใช่ข้อผิดพลาดร้ายแรงที่จับได้อีกต่อไปใน php 7 แต่ "ข้อยกเว้น" จะถูกโยนทิ้ง เป็น "ข้อยกเว้น" (ในคำพูดที่ทำให้ตกใจ) ที่ไม่ได้มาจากข้อยกเว้นแต่ข้อผิดพลาด ; มันยังคงเป็นThrowableและสามารถจัดการได้ด้วยบล็อก try-catch ตามปกติ ดูhttps://wiki.php.net/rfc/throwable-interface

เช่น

<?php
class ClassA {
  public function method_a (ClassB $b) { echo 'method_a: ', get_class($b), PHP_EOL; }
}
class ClassWrong{}
class ClassB{}
class ClassC extends ClassB {}


foreach( array('ClassA', 'ClassWrong', 'ClassB', 'ClassC') as $cn ) {
    try{
      $a = new ClassA;
      $a->method_a(new $cn);
    }
    catch(Error $err) {
      echo "catched: ", $err->getMessage(), PHP_EOL;
    }
}
echo 'done.';

พิมพ์

catched: Argument 1 passed to ClassA::method_a() must be an instance of ClassB, instance of ClassA given, called in [...]
catched: Argument 1 passed to ClassA::method_a() must be an instance of ClassB, instance of ClassWrong given, called in [...]
method_a: ClassB
method_a: ClassC
done.

คำตอบเก่าสำหรับเวอร์ชันก่อน php7:
http://docs.php.net/errorfunc.constantsพูดว่า:

E_RECOVERABLE_ERROR (จำนวนเต็ม)
ข้อผิดพลาดร้ายแรงที่ตรวจจับได้ แสดงว่าอาจมีข้อผิดพลาดที่เป็นอันตรายเกิดขึ้น แต่ไม่ได้ทำให้เครื่องยนต์อยู่ในสถานะที่ไม่เสถียร หากข้อผิดพลาดไม่ถูกจับโดยจุดจับที่ผู้ใช้กำหนด (ดูเพิ่มเติมที่set_error_handler () ) แอปพลิเคชันจะยกเลิกเนื่องจากเป็น E_ERROR

ดูเพิ่มเติม: http://derickrethans.nl/erecoverableerror.html

เช่น

function myErrorHandler($errno, $errstr, $errfile, $errline) {
  if ( E_RECOVERABLE_ERROR===$errno ) {
    echo "'catched' catchable fatal error\n";
    return true;
  }
  return false;
}
set_error_handler('myErrorHandler');

class ClassA {
  public function method_a (ClassB $b) {}
}

class ClassWrong{}

$a = new ClassA;
$a->method_a(new ClassWrong);
echo 'done.';

พิมพ์

'catched' catchable fatal error
done.

แก้ไข: แต่คุณสามารถ "ทำให้" เป็นข้อยกเว้นที่คุณสามารถจัดการได้ด้วยบล็อกลองจับ

function myErrorHandler($errno, $errstr, $errfile, $errline) {
  if ( E_RECOVERABLE_ERROR===$errno ) {
    echo "'catched' catchable fatal error\n";
    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    // return true;
  }
  return false;
}
set_error_handler('myErrorHandler');

class ClassA {
  public function method_a (ClassB $b) {}
}

class ClassWrong{}

try{
  $a = new ClassA;
  $a->method_a(new ClassWrong);
}
catch(Exception $ex) {
  echo "catched\n";
}
echo 'done.';

ดู: http://docs.php.net/ErrorException


1
แน่นอนว่าสิ่งนี้ทำงานเหมือนข้อผิดพลาดร้ายแรงมากยกเว้นเมื่อคุณดูบันทึกเซิร์ฟเวอร์ของคุณคุณจะไม่พบมัน ขอบคุณ php: /
John Hunt

3
กล่าวอีกนัยหนึ่งคือคุณไม่สามารถจับข้อผิดพลาดที่จับได้ วิเศษมาก!
Paul d'Aoust

@ พอลอะไรทำให้คุณได้ข้อสรุปนี้?
VolkerK

3
โอ้ฉันแค่หมายความว่ามันไม่สามารถจับได้ในความหมายดั้งเดิม (โดยใช้บล็อก try / catch) วันนั้นฉันรู้สึกไม่พอใจเกี่ยวกับ PHP ดังนั้นเมื่อฉันพบว่ามัน 'จับได้' ในความหมายที่แตกต่างกันโดยสิ้นเชิงฉันจึงรู้สึกว่าต้องแสดงความคิดเห็น ไม่มีอะไรต่อต้านคำตอบที่ยอดเยี่ยมของคุณ (ซึ่งในความเป็นจริงฉันโหวตแล้ว); ความโกรธทั้งหมดของฉันคือ PHP เอง!
Paul d'Aoust

และฉันคิดว่าฉันมองข้ามบางสิ่งไป ;-) blog.codinghorror.com/php-sucks-but-it-doesnt-matter : D
VolkerK
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.