Hoe kan ik een “catchable fatal error” op PHP-type hints opvangen?

Ik probeer Type Hinting van PHP5 te implementeren in een van mijn klassen,

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

Correct gebruik:

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

productiefout:

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

Herhaalbare fatale fout: argument 1 doorgegeven aan ClassA::method_a() moet een instantie van ClassB zijn, instantie van ClassWrong gegeven…

Is het mogelijk om die fout op te vangen (omdat er “catchable” staat)? en zo ja, hoe?


Antwoord 1, autoriteit 100%

Update: dit is geen fatale fout meer in php 7. In plaats daarvan wordt een “uitzondering” gegenereerd. Een “uitzondering” (tussen aanhalingstekens) die niet is afgeleid van Uitzonderingmaar Fout; het is nog steeds een Throwableen kan worden afgehandeld met een normaal try-catch-blok. zie https://wiki.php.net/rfc/throwable-interface

Bijvoorbeeld

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

afdrukken

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.

Oud antwoord voor pre-php7-versies:
http://docs.php.net/errorfunc.constantszegt:

E_RECOVERABLE_ERROR ( geheel getal )
Vangbare fatale fout. Het geeft aan dat er een waarschijnlijk gevaarlijke fout is opgetreden, maar de Engine niet in een onstabiele staat heeft achtergelaten. Als de fout niet wordt opgevangen door een door de gebruiker gedefinieerde handle (zie ook set_error_handler ()), wordt de toepassing afgebroken omdat het een E_ERROR was.

zie ook: http://derickrethans.nl/erecoverableerror.html

bijv.

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

afdrukken

'catched' catchable fatal error
done.

edit: Maar je kunt er een uitzondering van maken die je aankunt met een try-catch-blok

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

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

Other episodes