Debug


Debug - 图1

Overview

Debug - 图2

PHP offers tools to debug applications with notices, warnings, errors and exceptions. The Exception class offers information such as the file, line, message, numeric code, backtrace etc. of where an error occurred. OOP frameworks like Phalcon mainly use this class to encapsulate this functionality and provide information back to the developer or user.

Despite being written in C, Phalcon executes methods in the PHP userland, providing the same debugging capabilities as other PHP based frameworks offer.

Exceptions

A very common way to control the flow of errors in your application (intentional or otherwise) is to use a try/catch block to catch exceptions. There are plenty of examples in our documentation demonstrating such blocks.

  1. <?php
  2. try {
  3. // ...
  4. } catch (\Exception $ex) {
  5. }

Any exception thrown within the block is captured in the variable $ex. A Phalcon\Exception extends the PHP Exception class. Using the Phalcon exception allows you to distinguish whether the exception was thrown from Phalcon related code or elsewhere.

The Exception class, exposes the following:

  1. <?php
  2. class Exception
  3. {
  4. /**
  5. * @var int
  6. */
  7. protected $code;
  8. /**
  9. * @var string
  10. */
  11. protected $file;
  12. /**
  13. * @var int
  14. */
  15. protected $line;
  16. /**
  17. * @var string
  18. */
  19. protected $message;
  20. public function __construct(
  21. string $message = ''
  22. [, int $code = 0
  23. [, Exception $previous = null ]]]
  24. );
  25. public function __toString() -> string;
  26. final public function getCode() -> int;
  27. final public function getFile() -> string;
  28. final public function getLine() -> int;
  29. final public function getMessage() -> string;
  30. final public function getPrevious() -> Exception;
  31. final public function getTrace() -> array;
  32. final public function getTraceAsString() -> string;
  33. final private function __clone() -> void;
  34. }

You can use the same method calls when using the Phalcon\Exception:

  1. <?php
  2. use Phalcon\Exception;
  3. try {
  4. // ...
  5. } catch (Exception $ex) {
  6. echo get_class($ex), ': ', $ex->getMessage(), PHP_EOL;
  7. echo ' File=', $ex->getFile(), PHP_EOL;
  8. echo ' Line=', $ex->getLine(), PHP_EOL;
  9. echo $ex->getTraceAsString();
  10. }

It’s therefore easy to find which file and line of the application’s code generated the exception, as well as the components involved in generating the exception:

  1. PDOException: SQLSTATE[28000] [1045] Access denied for user 'root'@'localhost'
  2. (using password: NO)
  3. File=/app/public/index.php
  4. Line=74
  5. #0 [internal function]: PDO->__construct('mysql:host=loca...', 'root', '', Array)
  6. #1 [internal function]: Phalcon\Db\Adapter\Pdo->connect(Array)
  7. #2 /app/public/index.php(74):
  8. Phalcon\Db\Adapter\Pdo->__construct(Array)
  9. #3 [internal function]: {closure}()
  10. #4 [internal function]: call_user_func_array(Object(Closure), Array)
  11. #5 [internal function]: Phalcon\Di->_factory(Object(Closure), Array)
  12. #6 [internal function]: Phalcon\Di->get('db', Array)
  13. #7 [internal function]: Phalcon\Di->getShared('db')
  14. #8 [internal function]: Phalcon\Mvc\Model->getConnection()
  15. #9 [internal function]: Phalcon\Mvc\Model::_getOrCreateResultset('Users', Array, true)
  16. #10 /app/app/controllers/SessionController.php(83):
  17. Phalcon\Mvc\Model::findFirst('email='[email protected]')
  18. #11 [internal function]: SessionController->startAction()
  19. #12 [internal function]: call_user_func_array(Array, Array)
  20. #13 [internal function]: Phalcon\Mvc\Dispatcher->dispatch()
  21. #14 /app/public/index.php(114): Phalcon\Mvc\Application->handle()
  22. #15 {main}

As demostrated above, it does not matter that Phalcon is compiled as a PHP extension. The exception information contains parameters and method calls that were involved in the call that generated the exception fragment above. Exception::getTrace() provides additional information if necessary.

Constructor

Phalcon\Debug provides visual aids as well as additional information for developers to easily locate errors produced in an application.

NOTE Please make sure that this component is not used in production environments, as it can reveal information about your server to attackers

The following screencast explains how it works:

To enable it, add the following to your bootstrap:

  1. <?php
  2. use \Phalcon\Debug;
  3. $debug = new Debug();
  4. $debug->listen();

or using a shorter syntax:

  1. <?php
  2. (new \Phalcon\Debug())->listen();

Any try/catch blocks must be removed or disabled to make this component work properly.

By default the component will listen for uncaught exceptions but not low severity errors (warnings, notices etc.). You can modify this behavior by passing relevant parameters in listen()

  • exceptions - boolean
  • lowSeverity - booleanIn the example below, do not listen to uncaught exceptions but listen to non silent notices or warnings (low severity):
  1. <?php
  2. use \Phalcon\Debug;
  3. $debug = new Debug();
  4. $debug->listen(false, true);

If your application flow is different, or do not wish to pass the parameters on listen(), you can always use listenExceptions() and listenLowSeverity():

  1. <?php
  2. use \Phalcon\Debug;
  3. $debug = new Debug();
  4. $debug
  5. ->listenExceptions()
  6. ->listenLowSeverity()
  7. ->listen();

Note that the listenExceptions() and listenLowSeverity() are ON switches. If you wish to switch listening to exceptions or low severity errors OFF you need to pass false in the listen() method.

Getters

There are a few getters available that offer information about the component. Extending those could also change the behavior of the component visually.

  • getCssSources() - string Returns the stylesheets used to display the contents on screen
  • getJsSources() - string Returns the javascript files used to display the contents on screen
  • getVersion() - string Returns the link to the current version documentationExtending the component and overriding the getCssSources() for instance to return different CSS HTML directives will change the appearance of the output on screen. The output CSS classes are based on Bootstrap CSS.

Setters

Phalcon\Debug also offers some setters to better customize the output when an error occurs in your application.

  • setShowBackTrace(bool $showBackTrace) - Show/hide the exception’s backtrace
  • setShowFileFragment(bool $showFileFragment) - Show/Hide the file fragment in the output (related to the exception)
  • setShowFiles(bool $showFiles) - Show/Hide the files in the backtrace
  • setUri(string $uri) - The base URI for static resources (see also the Getters section for customization of the component)

Variables

You can also use the debugVar() method, to inject any additional variables you want to present in the output. These are usually application specific variables. An example might be to show timing information for your application.

  1. <?php
  2. use \Phalcon\Debug;
  3. $debug = new Debug();
  4. $time = time();
  5. $debug
  6. ->debugVar('time', $time)
  7. ->listen();

To clear the variable stack, you can call clearVars().

Finally you can halt execution of your application and trigger showing a backtrace by calling halt()

  1. <?php
  2. use \Phalcon\Debug;
  3. $debug = new Debug();
  4. $debug->listen();
  5. // .....
  6. if (12345 === $password) {
  7. $debug->halt();
  8. }

Blacklisting output

As mentioned above, the component must not be enabled in production environments. Since Phalcon cannot control this behavior, there is a built in blacklisting feature that allows the developer to blacklist certain pieces of information that they do not wish to be displayed on screen, just in case. These are elements of the $_REQUEST and $_SERVER arrays.

  1. <?php
  2. use \Phalcon\Debug;
  3. $debug = new Debug();
  4. $debug
  5. ->setBlacklist(
  6. [
  7. 'request' => ['some'],
  8. 'server' => ['hostname'],
  9. ]
  10. )
  11. ->listen();

In the example above, we will never show the element some from the $_REQUEST as well as the hostmane from $_SERVER. You can always add more elements not to be displayed, that exist in these two superglobals. This is particularly useful in case you forget to disable the component in your production environment. It is bad practice to leave it enabled but if you forget, at least certain key pieces of information about your host will not be visible to potential hackers.

The keys of the array elements to be hidden are case insensitive

Handlers

In order to catch exceptions and low severity errors, Phalcon\Debug makes use of onUncaughtException() and onUncaughtLowSeverity(). Most developers that use this component will never need to extend these methods. However, if you wish you can do so by extending the component and overriding these methods to manipulate the exception and return the output you require.

These two methods are being set as exception handlers using PHP’s set_exception_handler. When calling listenExceptions() the onUncaughtException() is registered, while when calling listenLowSeverity() the onUncaughtLowSeverity is registered.

Reflection and Introspection

Phalcon classes do not differ from any other PHP classes and therefore you can use the Reflection API or simply print any object to display its contents and state:

  1. <?php
  2. use Phalcon\Mvc\Router;
  3. $router = new Router();
  4. print_r($router);

The above example prints the following:

  1. Phalcon\Mvc\Router Object
  2. (
  3. [_dependencyInjector:protected] =>
  4. [_module:protected] =>
  5. [_controller:protected] =>
  6. [_action:protected] =>
  7. [_params:protected] => Array
  8. (
  9. )
  10. [_routes:protected] => Array
  11. (
  12. [0] => Phalcon\Mvc\Router\Route Object
  13. (
  14. [_pattern:protected] => #^/([a-zA-Z0-9\_]+)[/]{0,1}$#
  15. [_compiledPattern:protected] => #^/([a-zA-Z0-9\_]+)[/]{0,1}$#
  16. [_paths:protected] => Array
  17. (
  18. [controller] => 1
  19. )
  20. [_methods:protected] =>
  21. [_id:protected] => 0
  22. [_name:protected] =>
  23. )
  24. [1] => Phalcon\Mvc\Router\Route Object
  25. (
  26. [_pattern:protected] => #^/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)(/.*)*$#
  27. [_compiledPattern:protected] => #^/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)(/.*)*$#
  28. [_paths:protected] => Array
  29. (
  30. [controller] => 1
  31. [action] => 2
  32. [params] => 3
  33. )
  34. [_methods:protected] =>
  35. [_id:protected] => 1
  36. [_name:protected] =>
  37. )
  38. )
  39. [_matchedRoute:protected] =>
  40. [_matches:protected] =>
  41. [_wasMatched:protected] =>
  42. [_defaultModule:protected] =>
  43. [_defaultController:protected] =>
  44. [_defaultAction:protected] =>
  45. [_defaultParams:protected] => Array
  46. (
  47. )
  48. )

XDebug

XDebug is an amazing tool that complements the debugging of PHP applications. It is also a C extension for PHP, and you can use it together with Phalcon without additional configuration or side effects.

Once you have xdebug installed, you can use its API to get a more detailed information about exceptions and messages.

We highly recommend using the latest version of XDebug for a better compatibility with Phalcon

The following example implements xdebug_print_function_stack to stop the execution and generate a backtrace:

  1. <?php
  2. use Phalcon\Mvc\Controller;
  3. class SignupController extends Controller
  4. {
  5. public function indexAction()
  6. {
  7. }
  8. public function registerAction()
  9. {
  10. $name = $this->request->getPost('name', 'string');
  11. $email = $this->request->getPost('email', 'email');
  12. // Stop execution and show a backtrace
  13. return xdebug_print_function_stack('stop here!');
  14. $user = new Users();
  15. $user->name = $name;
  16. $user->email = $email;
  17. // Store and check for errors
  18. $user->save();
  19. }
  20. }

For the above example, Xdebug will also show us the variables in the local scope as well as a backtrace:

  1. Xdebug: stop here! in /app/app/controllers/SignupController.php
  2. on line 19
  3. Call Stack:
  4. 0.0383 654600 1. {main}() /app//public/index.php:0
  5. 0.0392 663864 2. Phalcon\Mvc\Application->handle()
  6. /app/public/index.php:37
  7. 0.0418 738848 3. SignupController->registerAction()
  8. /app/public/index.php:0
  9. 0.0419 740144 4. xdebug_print_function_stack()
  10. /app/app/controllers/SignupController.php:19

Xdebug offers several ways to get debug and trace information regarding the execution of your application using Phalcon. You can check the XDebug documentation for more information.

To set up Xdebug for PHPStorm you can check this article.