Heim > Artikel > PHP-Framework > Ausnahmebehandlung für die Laravel-Kernanalyse (Code)
Der Inhalt dieses Artikels befasst sich mit der Ausnahmebehandlung (Code) der Laravel-Kernanalyse. Ich hoffe, dass er für Freunde hilfreich ist.
Die Ausnahmebehandlung ist eine sehr wichtige, aber am häufigsten übersehene Sprachfunktion in der Programmierung. Sie bietet Entwicklern einen Mechanismus zur Behandlung von Programmlaufzeitfehlern. Die korrekte Ausnahmebehandlung kann Lecks verhindern Benutzern zur Verfügung gestellt, wodurch Entwicklern ein vollständiger Fehler-Traceback-Stack zur Verfügung gestellt wird und gleichzeitig die Robustheit des Programms verbessert wird.
In diesem Artikel gehen wir kurz auf die in Laravel bereitgestellten Ausnahmebehandlungsfunktionen ein und sprechen dann über einige Praktiken zur Verwendung der Ausnahmebehandlung in der Entwicklung, die Verwendung benutzerdefinierter Ausnahmen und die Erweiterung der Ausnahmebehandlungsfunktionen von Laravel.
Ausnahmehandler registrieren
Hier müssen wir zur Bootstrap-Phase zurückkehren, bevor der Kernel die Anfrage verarbeitet, die Laravel schon oft im Abschnitt IlluminateFoundationBootstrapHandleExceptions festgelegt hat der Bootstrap-Phase. Systemausnahmebehandlungsverhalten und Registrierung des globalen Ausnahmehandlers:
class HandleExceptions { public function bootstrap(Application $app) { $this->app = $app; error_reporting(-1); set_error_handler([$this, 'handleError']); set_exception_handler([$this, 'handleException']); register_shutdown_function([$this, 'handleShutdown']); if (! $app->environment('testing')) { ini_set('display_errors', 'Off'); } } public function handleError($level, $message, $file = '', $line = 0, $context = []) { if (error_reporting() & $level) { throw new ErrorException($message, 0, $level, $file, $line); } } }
set_Exception_handler([$this, 'handleException']) registriert die handleException-Methode von HandleExceptions als globale Handlermethode des Programms:
public function handleException($e) { if (! $e instanceof Exception) { $e = new FatalThrowableError($e); } $this->getExceptionHandler()->report($e); if ($this->app->runningInConsole()) { $this->renderForConsole($e); } else { $this->renderHttpResponse($e); } } protected function getExceptionHandler() { return $this->app->make(ExceptionHandler::class); } // 渲染CLI请求的异常响应 protected function renderForConsole(Exception $e) { $this->getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); } // 渲染HTTP请求的异常响应 protected function renderHttpResponse(Exception $e) { $this->getExceptionHandler()->render($this->app['request'], $e)->send(); }
Im Prozessor werden Ausnahmen hauptsächlich über die Berichtsmethode von ExceptionHandler gemeldet. Hier werden Ausnahmen in der Datei storage/laravel.log aufgezeichnet und dann wird die Ausnahmeantwort entsprechend dem Anforderungstyp gerendert, um eine Ausgabe zu generieren an den Kunden. Der ExceptionHandler ist hier eine Instanz der AppExceptionsHandler-Klasse. Er wurde zu Beginn des Projekts im Service-Container registriert:
// bootstrap/app.php /* |-------------------------------------------------------------------------- | Create The Application |-------------------------------------------------------------------------- */ $app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') ); /* |-------------------------------------------------------------------------- | Bind Important Interfaces |-------------------------------------------------------------------------- */ ...... $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class );
Hier ist übrigens die Funktion set_error_handler Funktion, da in einigen alten Codes oder Klassenbibliotheken die Funktion „trigger_error“ von PHP zum Auslösen von Fehlern verwendet wird. Der Ausnahmehandler kann daher nur Ausnahmen, aber keine Fehler verarbeiten. Um mit alten Klassenbibliotheken kompatibel zu sein, wird daher normalerweise set_error_handler zum Registrieren verwendet Globale Fehlerbehandlung: Konvertieren Sie den Fehler nach dem Abfangen des Fehlers in der Methode in eine Ausnahme und lösen Sie ihn erneut aus, sodass alle Codes im Projekt Ausnahmeinstanzen auslösen können, wenn sie nicht korrekt ausgeführt werden.
/** * Convert PHP errors to ErrorException instances. * * @param int $level * @param string $message * @param string $file * @param int $line * @param array $context * @return void * * @throws \ErrorException */ public function handleError($level, $message, $file = '', $line = 0, $context = []) { if (error_reporting() & $level) { throw new ErrorException($message, 0, $level, $file, $line); } }
Häufig verwendete Laravel-Ausnahmeinstanzen
Laravel löst entsprechende Ausnahmeinstanzen für häufige Programmausnahmen aus, sodass Entwickler diese Laufzeitausnahmen abfangen und entsprechend Ihren Anforderungen eine Folgeverarbeitung durchführen können Eigene Bedürfnisse (zum Beispiel: Aufrufen einer anderen Abhilfe in Catch, Aufzeichnen von Ausnahmen in Protokolldateien, Versenden von Alarm-E-Mails, Textnachrichten)
Hier werde ich einige Ausnahmen auflisten, die in der Entwicklung häufig auftreten, und erklären, unter welchen Umständen sie auftreten Beim normalen Codieren müssen Sie darauf achten, diese Ausnahmen im Programm abzufangen und sie gut zu behandeln, um das Programm robuster zu machen.
IlluminateDatabaseQueryException Diese Ausnahme wird ausgelöst, wenn beim Ausführen einer SQL-Anweisung in Laravel ein Fehler auftritt. Sie ist auch die am häufigsten verwendete Ausnahme und wird zum Erfassen von SQL-Ausführungsfehlern verwendet. Viele Leute beurteilen, ob die SQL-Anweisung nach der Ausführung ausgeführt wird, um zu bestimmen, ob die UPDATE-Anweisung erfolgreich ist. In diesem Fall ändert die ausgeführte UPDATE-Anweisung den Datensatzwert jedoch nicht , ist es nicht möglich, die geänderte Funktion zu verwenden, um festzustellen, ob das UPDATE erfolgreich ist. Wenn es außerdem während der Transaktionsausführung erfasst wird, kann QueryException die Transaktion im Catch-Block zurücksetzen.
IlluminateDatabaseEloquentModelNotFoundException Diese Ausnahme wird ausgelöst, wenn ein einzelner Datensatz nicht über die Methoden findOrFail und firstOrFail des Modells gefunden wird (find und first geben NULL zurück, wenn die Daten nicht gefunden werden können).
IlluminateValidationValidationException Diese Ausnahme wird ausgelöst, wenn die Anfrage die FormValidator-Validierung von Laravel nicht besteht.
IlluminateAuthAccessAuthorizationException Diese Ausnahme wird ausgelöst, wenn die Benutzeranfrage die Richtlinienüberprüfung von Laravel nicht besteht.
SymfonyComponentRoutingExceptionMethodNotAllowedException Die HTTP-Methode ist falsch, wenn Routing angefordert wird.
IlluminateHttpExceptionsHttpResponseException L Aravel verarbeitet HTTP-Anfragen nicht Bei Erfolg wird eine Ausnahme ausgelöst
Erweiterter Ausnahmehandler von Laravel
Wie oben erwähnt, hat Laravel AppExceptionsHandler erfolgreich als globalen Ausnahmehandler registriert und der Code wurde nicht abgefangen. Ausnahmen werden empfangen werden schließlich vom AppExceptionsHandler abgefangen. Der Prozessor meldet die Ausnahme zunächst und zeichnet sie in der Protokolldatei auf, rendert dann die Ausnahmeantwort und sendet die Antwort dann an den Client. Die integrierte Ausnahmebehandlungsmethode ist jedoch nicht einfach zu verwenden. Oft möchten wir Ausnahmen an E-Mail- oder Fehlerprotokollsysteme melden. Das folgende Beispiel dient dazu, Ausnahmen an das Sentry-System zu melden. Verwenden Sie:
public function report(Exception $exception) { if (app()->bound('sentry') && $this->shouldReport($exception)) { app('sentry')->captureException($exception); } parent::report($exception); }
und die Standard-Rendering-Methode. Das JSON-Format der bei der Formularvalidierung generierten Antwort unterscheidet sich häufig vom einheitlichen JOSN
-Format in unserem Projekt, was eine Anpassung des Verhaltens der Rendering-Methode erfordert .
public function render($request, Exception $exception) { //如果客户端预期的是JSON响应, 在API请求未通过Validator验证抛出ValidationException后 //这里来定制返回给客户端的响应. if ($exception instanceof ValidationException && $request->expectsJson()) { return $this->error(422, $exception->errors()); } if ($exception instanceof ModelNotFoundException && $request->expectsJson()) { //捕获路由模型绑定在数据库中找不到模型后抛出的NotFoundHttpException return $this->error(424, 'resource not found.'); } if ($exception instanceof AuthorizationException) { //捕获不符合权限时抛出的 AuthorizationException return $this->error(403, "Permission does not exist."); } return parent::render($request, $exception); }
自定义后,在请求未通过FormValidator验证时会抛出ValidationException, 之后异常处理器捕获到异常后会把错误提示格式化为项目统一的JSON响应格式并输出给客户端。这样在我们的控制器中就完全省略了判断表单验证是否通过如果不通过再输出错误响应给客户端的逻辑了,将这部分逻辑交给了统一的异常处理器来执行能让控制器方法瘦身不少。
使用自定义异常
这部分内容其实不是针对Laravel框架自定义异常,在任何项目中都可以应用我这里说的自定义异常。
我见过很多人在Repository或者Service类的方法中会根据不同错误返回不同的数组,里面包含着响应的错误码和错误信息,这么做当然是可以满足开发需求的,但是并不能记录发生异常时的应用的运行时上下文,发生错误时没办法记录到上下文信息就非常不利于开发者进行问题定位。
下面的是一个自定义的异常类
namespace App\Exceptions\; use RuntimeException; use Throwable; class UserManageException extends RuntimeException { /** * The primitive arguments that triggered this exception * * @var array */ public $primitives; /** * QueueManageException constructor. * @param array $primitives * @param string $message * @param int $code * @param Throwable|null $previous */ public function __construct(array $primitives, $message = "", $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->primitives = $primitives; } /** * get the primitive arguments that triggered this exception */ public function getPrimitives() { return $this->primitives; } }
定义完异常类我们就能在代码逻辑中抛出异常实例了
class UserRepository { public function updateUserFavorites(User $user, $favoriteData) { ...... if (!$executionOne) { throw new UserManageException(func_get_args(), 'Update user favorites error', '501'); } ...... if (!$executionTwo) { throw new UserManageException(func_get_args(), 'Another Error', '502'); } return true; } } class UserController extends ... { public function updateFavorites(User $user, Request $request) { ....... $favoriteData = $request->input('favorites'); try { $this->userRepo->updateUserFavorites($user, $favoritesData); } catch (UserManageException $ex) { ....... } } }
除了上面Repository列出的情况更多的时候我们是在捕获到上面列举的通用异常后在catch代码块中抛出与业务相关的更细化的异常实例方便开发者定位问题,我们将上面的updateUserFavorites 按照这种策略修改一下
public function updateUserFavorites(User $user, $favoriteData) { try { // database execution // database execution } catch (QueryException $queryException) { throw new UserManageException(func_get_args(), 'Error Message', '501' , $queryException); } return true; }
在上面定义UserMangeException类的时候第四个参数$previous是一个实现了Throwable接口类实例,在这种情景下我们因为捕获到了QueryException的异常实例而抛出了UserManagerException的实例,然后通过这个参数将QueryException实例传递给PHP异常的堆栈,这提供给我们回溯整个异常的能力来获取更多上下文信息,而不是仅仅只是当前抛出的异常实例的上下文信息, 在错误收集系统可以使用类似下面的代码来获取所有异常的信息。
while($e instanceof \Exception) { echo $e->getMessage(); $e = $e->getPrevious(); }
异常处理是PHP非常重要但又容易让开发者忽略的功能,这篇文章简单解释了Laravel内部异常处理的机制以及扩展Laravel异常处理的方式方法。更多的篇幅着重分享了一些异常处理的编程实践,这些正是我希望每个读者都能看明白并实践下去的一些编程习惯,包括之前分享的Interface的应用也是一样。
Das obige ist der detaillierte Inhalt vonAusnahmebehandlung für die Laravel-Kernanalyse (Code). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!