Bagaimana saya bisa menangkap "kesalahan fatal yang dapat ditangkap" pada petunjuk jenis PHP?

96

Saya mencoba mengimplementasikan Type Hinting of PHP5 di salah satu kelas saya,

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

class ClassB {}
class ClassWrong{}

Penggunaan yang benar:

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

menghasilkan kesalahan:

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

Kesalahan fatal yang dapat ditangkap: Argumen 1 yang diteruskan ke ClassA :: method_a () harus berupa turunan dari ClassB, turunan ClassWrong diberikan ...

Apakah mungkin untuk menangkap kesalahan itu (karena dikatakan "dapat ditangkap")? dan jika ya, bagaimana?

hoball
sumber
4
Untuk referensi di masa mendatang: Pengecualian di mesin (untuk PHP 7) - Dimulai dengan PHP 7, kesalahan fatal mungkin terjadi. Ini juga untuk yang dibahas di sini "Kesalahan fatal yangE_RECOVERABLE_ERROR dapat ditangkap " ( ) karena ini ditangkap dimulai dengan PHP 7 ..
hakre

Jawaban:

113

Pembaruan: Ini bukan lagi kesalahan fatal yang bisa ditangkap di php 7. Sebaliknya sebuah "pengecualian" dilemparkan. Sebuah "pengecualian" (dalam tanda kutip ketakutan) yang tidak berasal dari Exception tetapi Error ; itu masih dapat dilempar dan dapat ditangani dengan blok coba-tangkap normal. lihat https://wiki.php.net/rfc/throwable-interface

Misalnya

<?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.';

cetakan

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.

Jawaban lama untuk versi pra-php7:
http://docs.php.net/errorfunc.constants mengatakan:

E_RECOVERABLE_ERROR (integer)
Kesalahan fatal yang dapat ditangkap. Ini menunjukkan bahwa terjadi kesalahan yang mungkin berbahaya, tetapi tidak meninggalkan Mesin dalam keadaan tidak stabil. Jika kesalahan tidak ditangkap oleh pegangan yang ditentukan pengguna (lihat juga set_error_handler () ), aplikasi dibatalkan karena itu adalah E_ERROR.

lihat juga: http://derickrethans.nl/erecoverableerror.html

misalnya

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.';

cetakan

'catched' catchable fatal error
done.

edit: Tapi Anda bisa "menjadikannya" pengecualian yang bisa Anda tangani dengan blok coba-tangkap

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.';

lihat: http://docs.php.net/ErrorException

VolkerK
sumber
1
Jadi tentu saja ini berperilaku sangat mirip dengan kesalahan fatal, kecuali ketika Anda melihat di log server Anda, Anda tidak akan menemukannya. Terima kasih php: /
John Hunt
3
jadi dengan kata lain Anda tidak bisa menangkap kesalahan yang bisa ditangkap. Hebat!
Paul d'Aoust
@Paul apa yang membawamu ke kesimpulan ini?
VolkerK
3
Oh, maksud saya itu tidak dapat ditangkap dalam pengertian tradisional (menggunakan blok coba / tangkap). Saya hanya merasa kesal tentang PHP hari itu, jadi ketika saya mengetahui bahwa itu 'dapat ditangkap' dalam arti yang sama sekali berbeda, saya merasa terdorong untuk berkomentar. Tidak ada yang bertentangan dengan jawaban Anda yang luar biasa (yang sebenarnya saya beri suara positif); semua kemarahan saya adalah untuk PHP itu sendiri!
Paul d'Aoust
Dan saya pikir saya telah melewatkan sesuatu ;-) blog.codinghorror.com/php-sucks-but-it-doesnt-matter : D
VolkerK