IntroductionWelcome| 00:00 | (music playing)
| | 00:04 | Hi! I'm John Peck, and welcome
to Debugging PHP Advanced Techniques.
| | 00:08 | In this course we'll look at
how to debug your PHP code effectively
| | 00:12 | using a variety of client and server-side tools.
| | 00:14 | I'll start by showing you
how to configure PHP to handle
| | 00:18 | and report warnings, notices and errors.
| | 00:20 | Next, I'll introduce Xdebug, including
installation and configuration,
| | 00:24 | then demonstrate how to best use Xdebug.
| | 00:26 | We'll be covering many tools and techniques,
including how to debug applications
| | 00:31 | using multiple browsers.
| | 00:33 | Finally, best practices for debugging
and profiling web application failures
| | 00:37 | and performance issues will be covered.
| | 00:39 | The next time an issue needs to be addressed,
a full toolkit of options will be available.
| | 00:44 | Now, let's get started
with Debugging PHP Advanced Techniques.
| | Collapse this transcript |
| Using the exercise files| 00:00 | In this course I'll be developing
in a Sandbox PHP environment.
| | 00:04 | The recommended configuration for the
host environment is PHP 5.3 or above
| | 00:09 | and Apache 2 or above.
| | 00:10 | Other Web servers such as Nginx or IIS
will not be covered in this course.
| | 00:15 | Setting up a Web server stack
is beyond the scope of this course.
| | 00:18 | If you do not already have a development server,
| | 00:22 | I recommend using a local development server
running on your workstation.
| | 00:24 | The Up and Running with Linux
for PHP Developers course here in
| | 00:28 | the lynda.com Online Training Library
will allow you to have an optimized virtual server
| | 00:32 | running like any other program
in your existing operating system.
| | 00:35 | I will be demonstrating using a
server created using this technique.
| | 00:39 | Alternatively, you can use
a Web server solution stack package
| | 00:42 | in your native operating system.
| | 00:43 | XAMPP from apachefriends.org
has distributions for Linux, Windows,
| | 00:49 | Mac OS X, and Solaris.
| | 00:51 | WampServer from wampserver.com
is explicitly for Windows and MAMP
| | 00:57 | from mamp.info is for Mac OS X only.
| | 00:59 | Each of these packages will allow you to
execute the exercise files found in this course.
| | 01:03 | Installing additional software within
your native operating system is covered
| | 01:07 | in the course, Installing Apache, MySQL
and PHP with David Gassner, here in the
| | 01:12 | lynda.com Online Training Library.
| | 01:15 | Regardless of the location of your
Web server, you will need
| | 01:18 | access to the commands line with
administrative credentials in order to install
| | 01:21 | and configure server software.
| | 01:23 | For Mac and Linux, the terminal allows
you to access the command line,
| | 01:27 | which includes access to the SSH command
if the site is hosted remotely.
| | 01:31 | For Windows, you can use the free program
PuTTY, to connect via SSH to
| | 01:35 | remote servers available from
the official PuTTY website.
| | 01:38 | I will be demonstrating writing code
and debugging interactions using the
| | 01:42 | NetBeans 7.2 IDE bundle for PHP.
| | 01:45 | NetBeans is a free, open-source and
cross-platform integrated development
| | 01:49 | environment from netbeans.org
that also supports the Xdebug PHP extension.
| | 01:54 | The goal of the course is to teach
debugging techniques, not how to use NetBeans.
| | 01:58 | I recognize that different IDEs implement
Xdebug interactions in different ways,
| | 02:03 | but the base principles remain
constant across some implementations.
| | 02:06 | The exercise files for this course are
contained in folders by chapter and movie.
| | 02:11 | On my workstation, I have them
in a folder named sandbox that my
| | 02:15 | virtualized Linux server can access.
| | 02:17 | Depending on your web server configuration,
you may need to store these files
| | 02:20 | in a different place, such as a remote
Web server or in a folder accessible
| | 02:24 | by a local Apache and PHP stack.
| | 02:26 | Included in the exercise files are a
number of free PHP libraries,
| | 02:30 | including ChromePHP, FirePHPCore,
PHP_Debug and Webgrind.
| | 02:36 | No configuration is necessary and
usage will be described during the course.
| | 02:39 | A final note, as different Web hosts
and configurations serve content
| | 02:44 | from different URLs, the address you see
in my browser may not exactly match
| | 02:49 | what you see on your workstation.
| | 02:50 | Additionally, the location shown in
the command prompt demonstrations
| | 02:53 | will differ depending on the location of site
files and the configuration of your server.
| | 02:57 | The software configuration will be very similar,
if not identical across platforms.
| | Collapse this transcript |
| What you should know| 00:00 | Before starting this course,
you should have a basic knowledge
| | 00:03 | of the PHP language and
have written a few scripts.
| | 00:06 | Without this background, you may lack
the context necessary to understand
| | 00:09 | what you are doing,
which will not serve you well.
| | 00:12 | If you are looking for some background
or a refresher, I recommend
| | 00:16 | PHP with MySQL Essential Training with
Kevin Skoglund here in the
| | 00:20 | lynda.com Online Training Library.
| | 00:22 | A basic understanding of object-oriented
programming in PHP is also assumed
| | 00:26 | in this course, as debugging
problems encountered when interacting
| | 00:29 | with objects will be covered.
| | 00:31 | If you would like some more background,
see Object-Oriented Programming with PHP
| | 00:35 | here in the lynda.com Online Training Library.
| | 00:38 | Finally, if you are unfamiliar
with configuring Web server components,
| | 00:42 | check out the course Installing Apache, MySQL
and PHP with David Gassner here in the
| | 00:47 | lynda.com Online Training Library for a
comprehensive perspective on how to best
| | 00:51 | manage the solution stack.
| | Collapse this transcript |
|
|
1. Built-In PHP DebuggingExploring PHP error levels and consequences| 00:00 | Many years ago, the computer I shared with
my family had a program that executed on login
| | 00:04 | that would randomly display
a funny phrase or joke.
| | 00:08 | One of them is stuck with me.
| | 00:10 | I did it! I found the program's last bug,
bug, bug, bug, bug, bug, bug.
| | 00:14 | It worked on multiple levels,
the joy of finding a problem
| | 00:17 | and the humorous weirdness of a problem
manifesting within the error message itself.
| | 00:21 | As a software developer, I write computer programs
to perform specific tasks
| | 00:25 | in order to solve problems.
| | 00:27 | When I write programs in PHP,
I'm conforming to the specifications and rules
| | 00:31 | of both the language and the limitations
of the server environment so the
| | 00:35 | solutions need to be within those boundaries.
| | 00:37 | What happens when I bend or break these rules?
| | 00:40 | An error or a mistake will cause the program
to behave erratically or fail.
| | 00:45 | So what is debugging?
| | 00:47 | In its purest sense, debugging is
the act of identifying and removing errors
| | 00:51 | from a computer program.
| | 00:52 | PHP provides a number of built-in mechanisms
for debugging scripts by detecting
| | 00:56 | and reporting these errors.
| | 00:58 | In order to understand these reports,
some perspective into why they are created
| | 01:02 | and what they mean is necessary.
| | 01:04 | I'll start by describing how PHP works.
| | 01:07 | PHP is an interpreted language,
which means scripts are indirectly executed
| | 01:11 | by an interpreting program.
| | 01:13 | There are a number of advantages
to this approach, including
| | 01:16 | platform flexibility, smaller program size,
and dynamic typing, where values
| | 01:21 | have types and variables do not.
| | 01:23 | Some of the drawbacks
of an interpreted language are that,
| | 01:26 | in addition to decreased efficiency,
some kinds of errors cannot be detected
| | 01:30 | until that specific piece of the program is executed.
| | 01:33 | This is in contrast to compiled programs,
where the language code is converted
| | 01:37 | into machine code, and the compilation
of the entire program is halted
| | 01:41 | when a bad enough error is detected.
| | 01:43 | In computer programming, there
are two distinct kinds of errors.
| | 01:47 | A syntax error occurs when there is a
violation of the programming language's
| | 01:51 | set of rules that define the possible combination
of symbols in correctly-structured programs.
| | 01:56 | In short, the source code
broke the rules of the language.
| | 02:00 | Typically, execution or compilation
is halted and cannot proceed.
| | 02:05 | This abnormal termination
is colloquially referred to as a crash.
| | 02:10 | In contrast, illogical error,
also known as a semantic error, occurs when
| | 02:14 | the program operates incorrectly, but was structured
correctly within the rules of the language.
| | 02:19 | Rather than breaking the rules,
the problem is a failure of purpose
| | 02:23 | and unexpected behavior is the result.
| | 02:26 | PHP provides a number of low-level mechanisms
for detecting and reporting problems
| | 02:30 | with the execution of a script.
| | 02:32 | By providing a standardized structure,
developers have a clear expectation
| | 02:36 | of how the program will perform
in exceptional conditions,
| | 02:40 | like what conditions will cause a crash.
| | 02:42 | These problems are separated into a
hierarchy of error reporting levels
| | 02:47 | where there are distinctions made
about the severity and consequences of the error,
| | 02:50 | along with when the problem occurs.
| | 02:53 | There are three distinct severities of
problems in PHP, from least to most severe.
| | 02:58 | A notice is a non-fatal advisory
that while execution worked,
| | 03:03 | there is a good probability
that there is room for improvement.
| | 03:06 | A warning is also non-fatal, but is more severe.
| | 03:09 | A warning indicates that there's a strong possibility
that errors will occur in the future.
| | 03:13 | And an error is fatal,
meaning either the script cannot be interpreted
| | 03:17 | or during execution the program exceeds
its boundaries and was terminated.
| | 03:22 | Some referred to these crashes as the
"white screen of death," as often
| | 03:26 | fatal errors occur before renderable
content is sent to the browser,
| | 03:30 | so the browser shows nothing, but a blank page.
| | 03:33 | There are two distinct times when problems occur.
| | 03:36 | Compile time, which is generated
by the PHP parser when the script is
| | 03:40 | interpreted before it can be executed;
and run time, when
| | 03:44 | the script is interpreted correctly by the
parser and the problem occurs during execution.
| | 03:49 | Given the context of the severity
and timing, I can describe
| | 03:52 | how PHP reports these problems.
| | 03:54 | As of PHP 5.4, there are 16 distinct
error reporting levels that encompass
| | 03:59 | these problem severities in times.
| | 04:02 | Each level has a constant name and integer value.
| | 04:05 | Generally, developers have no practical need
to know the integer values,
| | 04:09 | as the error levels should only be
referred to in code by their constant name.
| | 04:13 | When configuring error reporting,
the integer values of these error levels
| | 04:17 | are combined using a bit mask and
the resulting integer is used
| | 04:20 | as a bit field by the interpreter.
| | 04:22 | I'm going to describe the most common error levels.
| | 04:25 | Later, I will provide examples of each,
practically demonstrating
| | 04:29 | how each of these error levels are triggered
and show you how to resolve them.
| | 04:32 | E_ERROR is a fatal run-time error
that cannot be recovered from,
| | 04:37 | halting script execution and resulting in a crash.
| | 04:40 | Examples include running out of memory.
| | 04:42 | E_WARNING, which is a run-time warning,
which means a nonfatal error
| | 04:47 | that does not halt execution of the script.
| | 04:49 | E_PARSE, which is a compile-time parse error
generated by the PHP parser,
| | 04:54 | which prevents script execution from even starting.
| | 04:57 | E_NOTICE, which is a run-time notice,
meaning that there is a possibility
| | 05:02 | that an error occurred or that everything could
be fine and the script executed normally.
| | 05:06 | In practice, run-time notices typically
come from logical errors in the script.
| | 05:10 | E_STRICT, which is a compile-time notice
where PHP has detected
| | 05:15 | a forward compatibility issue in the code.
| | 05:17 | Introduced in PHP 5.0, E_STRICT is useful
for detecting older sloppy programming
| | 05:22 | and adhering to coding standards.
| | 05:23 | E_DEPRECATED, which is a run-time notice
that warns that code in the script
| | 05:28 | will not work in future versions of PHP.
| | 05:31 | And finally, E_ALL, which is a combination
of all errors, warnings and notices.
| | 05:35 | There is a small exception;
| | 05:37 | E_STRICT was not introduced
in E_ALL until PHP 5.4.
| | 05:42 | Given the context of what these error levels
actually mean, I'll demonstrate
| | 05:46 | how to control how PHP reports problems.
| | Collapse this transcript |
| Configuring PHP to report what went wrong| 00:00 | In PHP there are two configuration options
that control what errors are reported
| | 00:05 | and whether these errors are displayed.
| | 00:06 | Depending on the platform or software
distribution that is being used,
| | 00:10 | the initial configuration of your system
may be different from the default,
| | 00:14 | so I'll describe how to both
get and set these options.
| | 00:17 | Error reporting sets the error reporting level
with an integer representing
| | 00:21 | a bit field normally through a named constant.
| | 00:24 | By default, PHP reports everything except
E_NOTICE and for versions
| | 00:29 | prior to PHP 5.4, also excluding E_STRICT.
| | 00:33 | Display_errors determines whether or not
to display errors to the user.
| | 00:36 | It's either 1 (on) or 0 (off).
| | 00:40 | By default, display_errors is set to 1 (on),
meaning errors are shown to the user.
| | 00:44 | Display_errors should only be set to 1 (on)
for development servers
| | 00:48 | and never shown to users,
as this both confuses unskilled users
| | 00:52 | and provides context for malicious users.
| | 00:54 | Error logging will be covered in-depth
in the next segment.
| | 00:57 | There are four places where error_reporting
and display_errors can be set
| | 01:01 | in order of increasing priority and granularity.
| | 01:04 | PHP.ini, which is the PHP configuration file,
which requires
| | 01:09 | a server restart and affects the entire server;
| | 01:14 | httpd.conf, this is the Apache server configuration
file and editing requires a server restart as well.
| | 01:18 | It also requires to allow override options
or allow override all privileges;
| | 01:23 | htaccess, which are directory level
configuration files for PHP does not require
| | 01:29 | a server restart, but isn't always available
and also requires allow override options
| | 01:33 | or allow override all privileges.
| | 01:36 | And finally, run time, which is in the
script itself and it's always available.
| | 01:41 | Now depending on the level of
administrative access available,
| | 01:45 | it may be possible that the only option
available is run time configuration.
| | 01:49 | However, there are some configuration options
that cannot be changed at run time,
| | 01:52 | so access to php.ini is preferred.
| | 01:56 | I will demonstrate how to edit php.ini
and to set these options at run time,
| | 02:01 | but not the other configuration files
out of interest of focusing on PHP
| | 02:05 | and not Apache server configuration.
| | 02:07 | The first method I will demonstrate
is editing php.ini, which will arbitrarily
| | 02:12 | set the configuration for every site
using that Web server.
| | 02:15 | On a development server, this is optimal
and easy, but this technique
| | 02:19 | may not be appropriate in all circumstances.
| | 02:21 | Use your best judgment.
| | 02:23 | To set error_report and display_errors
in php.ini, I need to first
| | 02:27 | locate the configuration file.
| | 02:29 | Similar to how defaults maybe different
across distributions and platforms,
| | 02:33 | the configuration file location can be
found in a number of different places.
| | 02:37 | Some solution stacks such as MAMP
actually generate the php.ini file,
| | 02:42 | so consult the documentation
if the following technique is not effective.
| | 02:45 | The easiest way to determine the location
of the configuration file is
| | 02:49 | using the function phpinfo() which outputs
information on the PHP configuration.
| | 02:54 | I'm going to switch to my IDE NetBeans
and open the demo.php file
| | 03:00 | from the exercise files.
| | 03:01 | I'll add one line, phpinfo, save,
then go to the browser and navigate
| | 03:08 | to where the test script is.
| | 03:09 | In my case, it's http.//sandbox.dev.8080.
| | 03:16 | A large amount of debugging information is shown.
| | 03:18 | I'm looking for loaded configuration file,
which contains the complete path
| | 03:22 | of the php.ini file.
| | 03:24 | In my environment, I can see that
the path is set to etcphp5apache2php.ini.
| | 03:32 | Now that I know where the file is,
I can edit it.
| | 03:34 | As I'm using a virtualized development server,
I'm going to SSH into it
| | 03:38 | then edit the file.
| | 03:40 | If you are not using a virtualized server
or you are using a hosted server
| | 03:43 | or solution stack, then the method used to edit
the file and restart the Apache Web server
| | 03:47 | will be slightly different, but the contents
of the file will be very similar.
| | 03:52 | First, I'll open a console then
I will SSH into the development environment.
| | 03:58 | Next, I will edit the configuration file
shown by phpinfo using administrative
| | 04:03 | credentials, sudo nano -w and then the file.
| | 04:09 | I will Search for the line containing
error_reporting =.
| | 04:15 | This is one of the lines that I edited in the
Up and Running with Linux for PHP Developers,
| | 04:18 | where I set the configuration
to every single notice, warning,
| | 04:23 | and error and added strict notices as well.
| | 04:25 | Above this line are a few suggested configurations
for different environments,
| | 04:29 | including the default value and production,
if not already set,
| | 04:33 | change the error_reporting to E_ALL | E_STRICT.
| | 04:36 | Next, Search for display_errors,
display_errors =, by default it's set to on,
| | 04:44 | if not, change it to on.
| | 04:46 | Exit by pressing Ctrl X and press Y
if you changed anything.
| | 04:50 | Finally, if there are changes that need
to take place, I will need to restart
| | 04:54 | the Apache Web server in order to allow
the new PHP configuration options to be read.
| | 04:59 | This will differ from server to server,
but the most common way to do this
| | 05:03 | and the way used for the virtualized development
server is to issue the following command,
| | 05:06 | sudo /etc/init.d/apache2restart.
| | 05:13 | Now, I'll go back to the IDE.
| | 05:16 | As I now know where the configuration setting is,
I no longer need the phpinfo function call,
| | 05:20 | so I'll remove it.
| | 05:22 | If you were unable to locate the configuration
file or do not have permission to change it,
| | 05:26 | I will now demonstrate how to set these values
at run time in the script itself.
| | 05:31 | A caveat, if display_errors is set at run time,
it won't have any effect
| | 05:36 | if the script has a fatal error before execution,
as the desired run time action does not get executed.
| | 05:41 | Additionally, if you are using a third-party host,
they may have disabled the use
| | 05:45 | of the function I will be demonstrating
for security reasons.
| | 05:48 | If so, find an alternative such as a local
development server that you directly administer.
| | 05:53 | First, I'm going to set the error_reporting
level using the function error_reporting,
| | 05:56 | which takes one parameter,
the integer value for the bit mask,
| | 06:01 | which I will use constants to create.
| | 06:03 | I'll use the same value as I did in php.ini.
| | 06:06 | I'll start with the comment, // Set error_
reporting, error_reporting (E_ALL | E_STRICT).
| | 06:18 | There are two functions that I will use to
interact with PHP options, ini get and ini set.
| | 06:24 | Ini get returns the value currently stored
for a given configuration option,
| | 06:28 | echo <h1>display_errors: before</h1>
| | 06:33 | and var_dump (ini_get('display_errors'));.
| | 06:37 |
| | 06:42 | Next, I'm going to intentionally trigger
a notice by attempting to access
| | 06:46 | as a variable that does not exist,
echo <h1>Triggering notice</h1>;
| | 06:52 | then var_dump ($error);
| | 06:58 | which does not exist.
| | 06:59 | I'm going to explicitly disable the display
of errors using the function ini_set
| | 07:04 | to override the php.ini option.
| | 07:07 | Ini_set takes two parameters, the name
of the option to be set and the new value.
| | 07:11 | So echo<h1>Setting errors</h1>;
| | 07:15 | then ini_set ('display_errors', 0).
| | 07:24 | I'll verify the new setting has been saved;
| | 07:28 | I can copy and paste this code
and then attempt to trigger the notice again.
| | 07:35 | Save, then return to the browser and refresh.
| | 07:40 | The first display_errors shows that
it was set to 1 by the php.ini.
| | 07:45 | When I triggered a notice by accessing error,
the undefined variable,
| | 07:49 | it is displayed to the screen
followed by the result of var_dump,
| | 07:52 | which correctly returned to null.
| | 07:53 | Next, the ini_set function call,
which does not display anything when called.
| | 07:58 | The value for display_errors is now
set to 0 and therefore the attempt
| | 08:02 | to trigger a notice fails.
| | 08:03 | Let's simplify the file a bit.
| | 08:05 | We'll continue not to display errors.
| | 08:06 | Do not display_errors.
| | 08:13 | Finally, to reiterate a point from earlier,
using ini_set to control display_errors
| | 08:17 | will only work if the script actually executes.
| | 08:21 | If there is a fatal error, the default
value set in php.ini will be used instead.
| | 08:26 | So if I just do error, this is an
invalid line, save then return
| | 08:31 | to the browser and refresh.
| | 08:34 | Despite attempting to disable error display,
a parse syntax error is displayed,
| | 08:39 | because the run time action was not executed.
| | 08:41 | Keep this in mind when configuring production
servers in preparing code for production.
| | 08:45 | I am going to switch back to the IDE
and clean up the demo file to prepare
| | 08:50 | for the rest of the course.
| | 08:51 | So I'm going to Display_errors and then
I'm going to intentionally
| | 08:57 | echo <h1>Triggering notice</h1>;
var_dump ($error);
| | 09:04 | and save.
| | 09:05 | Now that I've set error_reporting to
a development finding value
| | 09:09 | and I'm displaying errors to the screen,
I'll explore how to log errors to a file for analysis.
| | Collapse this transcript |
| Logging errors to file| 00:00 | There are a number of configuration options
relating to logging errors, but only a couple
| | 00:04 | are really necessary for most scenarios.
| | 00:07 | Similar to error_reporting options,
these options are set in php.ini
| | 00:12 | and can be overridden using ini set.
| | 00:14 | Log_errors, which defaults to off (0),
to not log errors.
| | 00:17 | I'm going to set log_errors to on to log_errors.
| | 00:20 | Use of 0 and 1 will also work as values,
which I'll need to use with ini set.
| | 00:25 | Log_errors_max_len is the length
of the error messages stored
| | 00:29 | in the logs measured in bytes.
| | 00:30 | The default is 1024 bytes.
| | 00:33 | If messages are getting truncated,
I can either set it to a higher value
| | 00:37 | or set it to 0 for unlimited message length.
| | 00:39 | Error_log, which sets the name of the file
where the script errors should be logged.
| | 00:43 | by default, it's Null and empty.
| | 00:46 | If log_errors is on and error log is null,
errors will be sent to the Apache
| | 00:50 | error log from the Web server or
standard error from a command line interface.
| | 00:54 | These three configuration options give me
the ability to enable error_logging.
| | 00:58 | As a best practice, PHP error should not
be included in the Apache error logs
| | 01:03 | as they're really separate contexts.
| | 01:05 | Additionally, the error_log should be
set to somewhere outside the Web root,
| | 01:09 | such as var/log/apache2/php.
| | 01:12 | For demonstration purposes, I'm going
to set the error_log to a local file
| | 01:15 | in the sandbox folder.
| | 01:17 | Finally, if space is at a premium and
the log files are getting very large,
| | 01:21 | set a logical value to the
log_errors maximum length.
| | 01:24 | First, I'll demonstrate how to edit php.ini.
| | 01:29 | Sudo nano -w /etc/php5/apache2/php.ini.
| | 01:38 | Search for log_errors =.
| | 01:42 | If it's not a ready set,
change it to log_errors = On.
| | 01:46 | Move down a couple of lines
to log_errors' max length.
| | 01:49 | For debugging purposes, it's helpful
to remove the limit of the size
| | 01:52 | of the error_logs, so set it to 0.
| | 01:55 | Finally, Search for error_log.
| | 01:58 | I'm going to explicitly set the log
file location to within the sandbox folder,
| | 02:02 | which in my case is
media/sf_sandbox/php_errors.log.
| | 02:08 | Press Ctrl+X to Exit, and if prompted,
Y to save the changes.
| | 02:12 | If there are changes,
restart the Apache Web server,
| | 02:15 | sudo/etc/init.d/apache2 restart.
| | 02:21 | I'm going to change directory to the
shared folder, cd/media/sf_sandbox/.
| | 02:26 | And start watching the error log using
the tail command to follow changes to php_errors.log.
| | 02:32 | Touch php_errors.log, then follow
the file, tail -f php_errors.log.
| | 02:41 | Open the browser and reload the page.
| | 02:45 | The notice for the undefined variable
is shown on the page and switching back
| | 02:50 | to the log is shown in the logs as well.
| | 02:53 | Next, I will demonstrate how to specify
these configuration options within a PHP script.
| | 02:57 | Remember, this will only work if the
script can be parsed, so if there's a fatal error,
| | 03:02 | the customization will not work.
| | 03:03 | I'm going to switch back to the IDE,
then at the top, I'll use ini_set again.
| | 03:09 | Instead of off and on, I'll use
the integer value in this context.
| | 03:12 | First, I'll turn on error logging.
| | 03:14 | So log errors, ini_set('log_errors')
and we'll set it to 1.
| | 03:24 | Then I'll remove the limit from the length,
No error log message max,
| | 03:32 | ini_set('log_errors_max len', 0).
| | 03:37 | And then I'll specify the location of the error log.
| | 03:42 | I'm going to put it in the same directory
as the demo script using a relative path
| | 03:46 | and I'll name it to something
slightly different to demonstrate
| | 03:49 | the precedence of where
configuration options are set.
| | 03:51 | Specify log_file, ini_set ('error_log',
and I'm going to set it to the
| | 03:58 | relative path to the current directory
and error_log.txt, save, then return
| | 04:04 | to the browser and reload.
| | 04:08 | Nothing changes, but if I look at the terminal,
I don't see the notice from the terminal.
| | 04:14 | Cancel the tail by pressing Ctrl+C,
then cat error_log.txt.
| | 04:20 | The notice will be shown, which means the local
ini set takes precedence over the php.ini.
| | 04:26 | Now that I've demonstrated how to turn
on php_error logging to a file,
| | 04:30 | I'm going to cleanup the demo file
a little bit.
| | 04:32 | Switching back to the IDE,
let's specify the same error_log file name
| | 04:36 | as I set in php.ini,
media/sf_sandbox/php_errors.log.
| | 04:47 | Remove the other test code and save the file.
| | 04:50 | Next, I'm going to demonstrate how to
intentionally trigger a number of common
| | 04:54 | php_errors and how to avoid
the problems in the first place.
| | Collapse this transcript |
| Triggering and repairing PHP errors| 00:00 | I'm going to demonstrate a number of different
kinds of errors then repair each of them.
| | 00:04 | As I will be removing each test code
when it's fixed, I will provide the code
| | 00:08 | in a separate exercise file.
| | 00:10 | The first kind of error
I will demonstrate is E_ERROR.
| | 00:13 | E_ERROR example where I will
intentionally run out of memory.
| | 00:20 | This is a fatal run time error
that cannot be recovered from,
| | 00:24 | halting script execution
and resulting in a crash.
| | 00:26 | I'll start by setting the memory limit to 1 kilobyte,
ini_set ('memory_limit', '1K');
| | 00:35 | then I'll create a giant object by casting
an array containing the numbers of 0 to 1,000
| | 00:40 | as an object, var_dump ((object) range (0, 1000)),
save then go to the browser and refresh.
| | 00:51 | The fatal error will be displayed
indicating that the system ran out of memory.
| | 00:54 | I'll return to the IDE and remove the artificially
low memory limit, save, then try again.
| | 01:04 | This time the contents of the object are
rendered correctly and the script does not crash.
| | 01:08 | Depending on the context of a script,
it may make sense to increase the memory limit
| | 01:12 | of PHP but coordinate with any system
administrators before making changes
| | 01:16 | that can potentially consume more
server resources than were expected.
| | 01:20 | Back to the IDE, erase the E_ERROR code.
| | 01:24 | I'm going to generate another fatal error,
this time an E_PARSE error for bad syntax,
| | 01:28 | E_PARSE error - bad syntax.
| | 01:33 | I'm going to leave off the trailing semicolon,
which is going to cause a parse error,
| | 01:37 | echo 'fail', save the file.
| | 01:40 | NetBeans is going to mark this line as
being an error and underlines it,
| | 01:44 | and if I hover my cursor,
I'll see that this is a syntax error.
| | 01:47 | Go to the browser and refresh.
| | 01:51 | A fatal syntax error has been triggered and
explicitly states that the semicolon is missing.
| | 01:55 | In this particular case, it's an easy fix.
| | 01:58 | I'll switch back and just add a semicolon.
| | 02:01 | Next, I'll create another real-world parse error,
unmatched brackets.
| | 02:06 | So if (True) { save and refresh.
| | 02:10 | This time I see the same unexpected end, but
the error says nothing about the missing bracket.
| | 02:15 | This is often a problem, especially
when refactoring code with multiple
| | 02:18 | nested if statements.
| | 02:20 | The use of coding standard help
avoid this kind of problem by enforcing
| | 02:23 | spacing and indentation.
| | 02:25 | To fix, go back to the IDE and
just add the missing bracket.
| | 02:29 | I'm going to remove the code and start over,
because I'm going to create an E_WARNING,
| | 02:34 | a nonfatal problem.
| | 02:37 | Previously I discussed how ini_set
may not be available on some third-party hosts.
| | 02:41 | For demonstration purposes,
I'm going to recreate that problem,
| | 02:44 | which will trigger an E_WARNING
for all the ini_sets in the demo.
| | 02:48 | From the terminal, edit php.ini again,
sudo nano -w/etc/php/5/apache2/php.ini.
| | 03:01 | Search for disable_functions = and add
ini_set to the end of the list, ini_set,
| | 03:10 | press Ctl X to Exit, Y to Save
and restart then Web server,
| | 03:14 | sudo /etc/init.d/apache2 restart.
| | 03:21 | Go back to the browser and refresh.
| | 03:24 | The only thing triggering a warning
is the disallowed function,
| | 03:27 | which in this case
is just generating a warning.
| | 03:29 | The solution in this case is to either
not use ini_set or allow the use of it again.
| | 03:34 | Return to the terminal, edit php.ini and remove
the ini_set from the disable functions directive.
| | 03:42 | Ctrl X and Y to Save.
| | 03:46 | Save, then restart the Web server,
return to the browser, and refresh.
| | 03:51 | The error messages are gone.
| | 03:53 | Going back to the IDE, I'm going to demonstrate
another nonfatal error level, E_NOTICE.
| | 04:00 | I typically see notices when I try
to do something goofy, like access
| | 04:03 | a variable, value or property that does not exist.
| | 04:06 | E_NOTICE - typically accessing something undefined.
| | 04:12 | First, I'll dump array which doesn't exist,
var_dump($array);
| | 04:17 | Next, I'll define array but
access a key that isn't set.
| | 04:21 | So $array = array ();
| | 04:25 | var_dump($array[0]);.
| | 04:27 | Finally, I'll create an empty class
and access a property that doesn't exist
| | 04:31 | named property, $object = new std(Class();
| | 04:37 | and then var_dump($object ->property);
| | 04:43 | save then return to the browser and refresh.
| | 04:47 | Three notices are displayed,
one for the undefined variable,
| | 04:51 | a second for the undefined array offset,
and a final one for the undefined object property.
| | 04:56 | To repair; only attempt to access things
that exist, there's a couple of ways
| | 05:00 | of dealing with this gracefully.
| | 05:01 | Return to the IDE, the best solution for the
undefined variable is to define the variable.
| | 05:07 | However, when attempting to access offsets
or properties, it is inappropriate
| | 05:11 | to just set the element in question.
So what should I do?
| | 05:14 | Use the isset function, which does not
trigger any errors of the thing being
| | 05:18 | checked does not exist.
| | 05:19 | So in this case,
if (isset($array [0])) { then var_dump.
| | 05:26 | This is also good logic, as if I'm trying
to access something and it doesn't exist,
| | 05:29 | that it probably is not a good thing
and additional action should be taken.
| | 05:34 | The same isset technique
works for objects as well.
| | 05:37 | So, if (isset($object->property)) {,
save and then return to the browser and refresh.
| | 05:47 | Instead of a number of notices,
the empty array is displayed.
| | 05:51 | Two more error levels remain.
| | 05:53 | Back to the IDE, I'm going to
remove the previous test content.
| | 05:57 | I'm going to start with E_STRICT,
which enforces best practices
| | 06:02 | and is intended to prevent sloppy programming.
| | 06:04 | One of the most common ways to trigger
an E_STRICT warning is treating a method
| | 06:09 | as static that isn't
E_STRICT - mixing scopes.
| | 06:14 | I'll create a simple class called strict
with one function named trigger,
| | 06:18 | which will just display the word triggered, class
Strict { function trigger () { echo 'triggered';
| | 06:27 | Without instantiating strict,
I'll call trigger, Strict::trigger();
| | 06:33 | save, then return to the browser and refresh.
| | 06:37 | I get a rather verbose notice telling
me not to mix my scopes by statically
| | 06:41 | calling a nonstatic method.
| | 06:42 | Back to the IDE. This is a quick fix,
make the function static.
| | 06:47 | Alternatively, I could instantiate strict
then instead of using the scope
| | 06:51 | resolution operator, I could
call the function normally.
| | 06:54 | If I didn't make it static,
just do $strict = new Strict ();
| | 07:02 | and then $strict->trigger();
| | 07:05 | Either way use your best judgment
given the context.
| | 07:08 | Save and return to the browser and refresh.
| | 07:12 | Triggered is shown and none of notices are.
| | 07:15 | Back to the IDE and removing the old content,
I'll demonstrate the final error level,
| | 07:19 | which is E_DEPRECATED, which is
shown when I try to use something
| | 07:23 | that is no longer supported and will be removed,
E_DEPRECATED - something will be removed soon.
| | 07:30 | I'll demonstrate using two deprecated techniques.
| | 07:33 | The first is creating a new object by reference.
| | 07:37 | So $deprecated = & stdClass();
| | 07:42 | then var_dump($deprecated);
| | 07:45 | Next is the split function.
| | 07:49 | I see these both in legacy PHP 4 code,
var_dump(split(' , ', one, two, three))
| | 08:00 | save then return to the browser and refresh.
| | 08:04 | Both worked, but both also
trigger E_DEPRECATED notices.
| | 08:08 | The repairs are straightforward in this case.
| | 08:10 | In the IDE, remove the ampersand sign
as PHP 5 creates objects correctly.
| | 08:16 | The split function was replaced with explode
which takes the same parameters.
| | 08:21 | Save the changes and test them in the browser.
| | 08:25 | Both function in the same way
just without the notices.
| | 08:28 | I have one more way of triggering errors
to demonstrate manually triggering an error,
| | 08:32 | which can be useful for logging custom errors.
| | 08:35 | The trigger_error function takes two
parameters, the string to be displayed
| | 08:39 | and an optional integer with the error level.
| | 08:42 | Now these error levels are different
than the ones I have demonstrated,
| | 08:45 | these are user error levels.
| | 08:47 | There are three of them.
| | 08:47 | E_USER_NOTICE, which is the default
level of trigger error, E_USER_WARNING
| | 08:54 | and E_USER_ERROR. Go back to the
IDE and remove the test code.
| | 09:00 | I'm going to manually trigger
each of the error levels
| | 09:03 | trigger_error {'Custom notice', which I
will use the constant for E_USER_NOTICE);
| | 09:11 | and trigger_error{'Custom
warning', E_USER_WARNING);
| | 09:19 | and then trigger_error{
'Custom error', E_USER_ERROR);
| | 09:25 | I'm going to add a final line which
will never be reached due to the triggering
| | 09:30 | of the E_USER_ERROR, echo 'will not execute';
| | 09:34 | save and then go back to
the browser and refresh.
| | 09:39 | The notice, warning and error shown
in the final echoed 'will not execute'
| | 09:43 | is not shown, as the fatal error
was triggered and shutdown PHP.
| | 09:47 | In the next segment, I will demonstrate
how to gracefully handle fatal errors.
| | Collapse this transcript |
| Gracefully handling fatal errors| 00:00 | While developers strive to write
fault tolerant and problem-free code,
| | 00:04 | inevitably fatal errors and crashes do occur.
| | 00:07 | Rather than just presenting a user
with a blank screen or interrupted output,
| | 00:11 | it's possible to programmatically
execute a function just before
| | 00:15 | a PHP completely shutsdown using
the PHP function register_shutdown_function.
| | 00:20 | As these functions execute during shutdown,
typically there is little context
| | 00:24 | as PHP has already been cleaning up.
| | 00:26 | I've heard this described as
writing a note after falling from a cliff.
| | 00:30 | However, the function error_get_last
will still work in this context
| | 00:34 | and will provide the line, file, error type
and message as an associative array.
| | 00:39 | I'm going to demonstrate how to register
a custom shutdown function
| | 00:42 | that will notify both the user and the administrator
of the problem, but with the caveat of
| | 00:46 | this will not work if the file containing
the register shutdown function has a parse error.
| | 00:51 | In the IDE, I'm going to start
by registering the shutdown function
| | 00:55 | just after the block of ini_sets.
| | 00:57 | Register_shutdown_function requires one parameter,
a string containing the name
| | 01:03 | of the function to call.
| | 01:04 | I'm going to name this function shutdown_notify.
| | 01:08 | Next, I'm going to define the function itself,
start with a comment.
| | 01:13 | Send a notification on a shutdown
caused by an error.
| | 01:19 | Next, the function itself which
takes no parameters.
| | 01:24 | Using the function error_get_last, get the
last error if any, so $error = error_get_last();.
| | 01:32 | If the error is not empty,
it returns an associative array.
| | 01:36 | One of the keys, type, contains
the integer value of the error level,
| | 01:41 | which I can use to determine
the kind of error;
| | 01:44 | if (!empty($error) && in_array($error['type'],
array(E_ERROR, E_ERROR, ))).
| | 02:00 | So if it's not empty and it's one
of those types,
| | 02:05 | then show a graceful message to the user.
| | 02:06 | It can have markup, but don't assume
any particular styles are available.
| | 02:10 | So echo'<h1>Sorry, something went horribly wrong;
| | 02:16 | the team has been notified.</h1>';.
| | 02:22 | For now, let's just show the contents
of error and the server
| | 02:26 | superglobal, var_dump($error);
| | 02:30 | and then var_dump($_SERVER);
| | 02:33 | save and return to the browser and refresh.
| | 02:37 | The three Triggered error levels
are shown and the last trigger error
| | 02:40 | was fatal and caused the shutdown.
| | 02:42 | Looking at the contents of the error,
I can see four keys and I can also see
| | 02:46 | the contents of the server superglobal.
| | 02:50 | This is very helpful information
for a programmer or administrator,
| | 02:53 | but shouldn't be shown to a user.
| | 02:55 | If the server has e-mail setup,
I can take this opportunity to send
| | 02:59 | a notification describing the problem.
| | 03:01 | Do be careful when doing this, as if there is
a major problem on a high-traffic site,
| | 03:05 | thousands of e-mails could be sent.
| | 03:07 | So consider writing a mechanism that
can throttle the volume of messages
| | 03:10 | by checking a local file.
| | 03:11 | Returning to the IDE, I'm going to remove
the var_dump and instead compose an e-mail,
| | 03:16 | start with a to, $to = 'user@example.com';.
| | 03:22 | Next, the subject which should provide
some high-level context,
| | 03:37 | $subject = "[{$_SERVER['SERVER_NAME]}] fatal error in
{$error['file']} on line {$error['line']}]";
| | 03:48 | Then I'll create a message.
| | 03:49 | I'll use var_export($error) then set the
second parameter to True to return the output.
| | 03:57 | I'll concatenate the end of line
character at the end to be clean.
| | 04:01 | I'll add to the message and
also export server superglobal.
| | 04:07 | Now that the message has been created,
simply use PHP's mail function.
| | 04:12 | I'm going to leave mail commented out for now,
so I don't send a large number of e-mails
| | 04:16 | to myself while demonstrating.
| | 04:17 | Mail $to, $subject and then the $message
and remember to comment it out and save.
| | 04:26 | Return to the browser and Reload.
| | 04:28 | The shutdown function is now triggered,
but instead of showing debugging
| | 04:32 | information to the user,
it's prepared it for e-mail.
| | 04:35 | Before I move on to third-party tools,
there is one more PHP debugging tool
| | 04:39 | that I would like to demonstrate, debug_backtrace.
| | Collapse this transcript |
| Deciphering backtraces| 00:00 | The PHP function, debug_backtrace
generates a backtrace.
| | 00:04 | A backtrace is a report containing
a sequence of nested function and method
| | 00:08 | calls to the point where the trace
is generated, which gives context
| | 00:12 | to a developer to know what happened.
| | 00:14 | This is especially useful when working
with frameworks and nested structures
| | 00:17 | with many file inclusions,
functions calling functions, and so forth.
| | 00:21 | Debug backtrace returns associative
arrays keyed by the frame, which is like
| | 00:25 | a depth in ascending order where the lowest
number is the last thing to be executed.
| | 00:30 | For each frame, you will be given the
function name, line and file if any,
| | 00:35 | class and object if any, and arguments.
| | 00:37 | I'm going to demonstrate how to generate
and read backtraces in order to get context.
| | 00:42 | Backtraces are excellent for development
but not for reporting errors,
| | 00:46 | and I'll show you why that is in a moment.
| | 00:48 | First, go to the IDE and navigate
to after the shutdown function.
| | 00:53 | I'm going to create a short sequence
of functions that call one another,
| | 00:56 | and at the end I'll display a backtrace.
| | 00:58 | I'll keep it simple, function A takes
an argument and passes a different argument
| | 01:03 | to function B. Function B also
takes an argument and calls function D.
| | 01:11 | Function D displays the content
of debug_backtrace on the screen.
| | 01:17 | So var_dump(debug_backtrace(});.
| | 01:20 | Finally, call the first function,
save then go to the browser and refresh.
| | 01:26 | The backtrace is rendered with frame zero
containing the last called function, function D.
| | 01:30 | Scrolling through I can see that each
of the functions in order that
| | 01:35 | they were called, and on the very last step,
the required ones that was used
| | 01:39 | to include the demo file into the exercise index.
| | 01:42 | It would be logical to want to include
a debug_backtrace in the fatal error behavior,
| | 01:46 | but it won't work
in the way one might expect.
| | 01:49 | Go back to the IDE and move the three
intentionally triggered errors
| | 01:54 | after the debug_backtrace in function D.
| | 01:58 | Then, add the same var_dump debug_backtrace
to notify shutdown after the echoed message
| | 02:03 | to the user, save then return
to the browser and refresh.
| | 02:09 | Scrolling to the bottom past the first
debug backtrace, I could see a second
| | 02:12 | debug_backtrace, but it's strangely empty.
| | 02:15 | This is due to other PHP shutdown functions
I mentioned previously.
| | 02:19 | Backtraces are useful but are they limited
to nonfatal errors? Not necessarily.
| | 02:24 | In the next chapter, I'll introduce Xdebug,
a PHP extension that provides
| | 02:29 | additional functionality for developments
that will, among other things,
| | 02:33 | produce backtraces on fatal errors.
| | 02:35 | Throughout this chapter, I've laid the
groundwork essential to understanding
| | 02:39 | how PHP handles errors and warnings, starting
with PHP error levels and consequences.
| | 02:44 | Next, I demonstrated how to configure PHP
to report what went wrong
| | 02:49 | and how to log those errors to file.
| | 02:50 | I intentionally triggered and repaired
a number of common kinds of PHP errors
| | 02:54 | then demonstrated a technique
for gracefully handling fatal errors.
| | 02:58 | Finally, I showed how backtraces can be
deciphered to give context into the call stack.
| | 03:03 | PHP has an additional mechanism for handling
object-oriented errors known as exceptions.
| | 03:08 | Exceptions can be triggered,
known as throwing, and handled
| | 03:12 | using a technique known as catching.
| | 03:14 | I've covered this topic in-depth
in a different course, Object-oriented
| | 03:17 | Programming with PHP here in the
lynda.com Online Training Library.
| | 03:21 | The two segments in particular
are Error Handling with Exceptions
| | 03:25 | and Customizing PHP Exceptions.
| | Collapse this transcript |
|
|
2. Introducing XdebugWhat is Xdebug and how can it be used?| 00:00 | While the core PHP distribution contains
many tools for debugging and error handling,
| | 00:04 | it does have some inherence limitations
such as the inability
| | 00:08 | to perform stack traces on fatal errors.
| | 00:10 | To provide this missing functionality
and to give additional introspection
| | 00:14 | into script operation, the PHP
extension Xdebug was created in 2002.
| | 00:19 | Currently at version 2.2.1, Xdebug
is a debugging and profiling tool
| | 00:25 | for use on development servers.
| | 00:27 | By providing stack and function
execution traces and error messages,
| | 00:31 | Xdebug allows fatal errors to be debugged
with the same clarity available during
| | 00:35 | normal program execution without the
limitation of the shutdown processes.
| | 00:40 | Xdebug is also a profiling tool,
which tracks how long it takes to execute
| | 00:44 | each part of a script, which is useful
for finding performance bottlenecks.
| | 00:48 | Additionally, Xdebug provides mechanism
for remote debugging allowing script execution
| | 00:52 | to be paused at any arbitrary point
and the contents of variables
| | 00:57 | to be read and manipulated.
| | 00:59 | Xdebug is a powerful debugging tool
and as such should not be used
| | 01:03 | on anything other than
private development servers.
| | 01:06 | There are a number of reasons for this.
| | 01:08 | First, it's a security risk in that it exposes
very low-level information about the execution
| | 01:11 | of a script, which provides malicious users
with privileged information.
| | 01:17 | Additionally, the remote debugging functionality
does not require any authentication
| | 01:20 | or encryption out of the box
leaving the proverbial door wide open.
| | 01:25 | Finally, Xdebug can record and collect
a large amount of information, which in turn
| | 01:29 | consumes more memory and processor resources
than a regular script execution.
| | 01:34 | For a developer, this difference is negligible
but for a public facing server,
| | 01:38 | the aggregate performance hit will be
significant enough to cause problems.
| | 01:42 | With this context, let's move on to
installing the Xdebug extension.
| | Collapse this transcript |
| Installing the Xdebug extension| 00:00 | If you are using a Web server stack
such as MAMP or WampServer then Xdebug
| | 00:05 | may be already available, so please refer
to the appropriate documentation in those cases.
| | 00:11 | These instructions assume that PECL
is already installed on the target server,
| | 00:15 | which is part of the PEAR packaging system.
| | 00:17 | If not, please install PEAR.
| | 00:20 | Additionally,
administrative credentials are required.
| | 00:24 | The following technique was adapted
from documentation from Xdebug.org.
| | 00:29 | Please refer to the documentation
for additional troubleshooting
| | 00:32 | and installation alternatives.
| | 00:34 | Netbeans.org also provides some
comprehensive installation instructions
| | 00:38 | with details not found on the Xdebug site.
| | 00:41 | By using PECL, Xdebug installation
is straightforward but does have some little
| | 00:46 | pain points that I will help mitigate.
| | 00:49 | From the terminal,
connect to the development server.
| | 00:54 | Next, use PECL to install Xdebug.
| | 00:57 | This performs the majority of the dirty work,
including the downloading and compiling,
| | 01:00 | but does not actually configure Apache,
so type the following command:
| | 01:04 | sudo pecl install xdebug,
it will ask me for my password.
| | 01:12 | When completed, take note of the line,
Installing, followed by a path.
| | 01:16 | This is where the extension was placed.
| | 01:18 | I can see that the file was placed in
/usr/lib/php5/20090626/xdebug.so.
| | 01:27 | Depending on your system configuration,
this may be slightly different.
| | 01:31 | There is a second line, which should be ignored.
| | 01:33 | You should add extension=Xdebug.so to php.ini.
| | 01:38 | Again, ignore this as this message
is created by PECL but not Xdebug.
| | 01:42 | This is a known minor issue.
| | 01:44 | Now that Xdebug is installed, I need
to configure PHP to load the extension.
| | 01:49 | Xdebug has a number of configuration options,
but for the time being
| | 01:53 | I'm just going to load the extension.
| | 01:54 | Edit the PHP configuration,
sudo nano-w /etc/php5/apache2/php.ini.
| | 01:57 | I'm going to press Esc+/
to navigate to the end of the file.
| | 02:08 | Add the following line, zend_extension=
followed by the path shown
| | 02:16 | in the PECL Xdebug installation.
So in my case, its
| | 02:17 | "/usr/lib/php5/20090626/xdebug.so"
Exit, Ctrl+X and Y to save.
| | 02:32 | Restart the Web server to allow the
PHP configuration changes to take effect,
| | 02:36 | sudo/etc/init.d/apache2 restart.
| | 02:40 |
| | 02:43 | Now that the Web server has restarted,
switch to the browser and reload the page.
| | 02:47 | If Xdebug was installed correctly,
each of the triggered error levels
| | 02:53 | will also have a stack trace after it.
| | 02:55 | If the stack traces are not seen,
check the previously mentioned installation
| | 02:59 | documentation for additional pointers.
| | 03:02 | Xdebug has been installed,
but where to go from here?
| | 03:05 | First, I'm going to discuss
how Xdebug handles variable display.
| | Collapse this transcript |
| Displaying variables with Xdebug| 00:00 | Xdebug replaces var_dump and var_export
with its own version, which includes
| | 00:05 | different colors and highlighting
for different types, limits on array elements
| | 00:09 | and object properties, a maximum depth
to prevent infinite recursion problems,
| | 00:14 | and string length to reduce the
chance of overloading the browser.
| | 00:18 | It's on by default, but is only enabled
if PHP is configured to render error messages
| | 00:23 | as HTML, and HTML errors are off by default.
| | 00:28 | Return to the terminal then edit the
PHP configuration again,
| | 00:33 | sudo nano -w /etc/php5/apache2/php.ini.
| | 00:33 | Press Ctrl+W to search for HTML_ERRORS =.
| | 00:48 | Change its value to On.
| | 00:49 | Then exit and save, then restart the Web server.
| | 00:56 | Return to the browser and refresh.
| | 01:01 | Immediately, the difference will be noticeable
and the notice, warning and fatal errors
| | 01:05 | are now displayed in a table.
| | 01:08 | The trigger error functions are clickable,
linking to the documentation on php.net.
| | 01:13 | Xdebug also adds an improved version
of PHP's debug_zval_dump called
| | 01:20 | xdebug_debug_zval, which includes
structured information about variables,
| | 01:25 | including type, value and reference count.
| | 01:29 | By using the variable name to look up
the variable, as opposed to passing
| | 01:32 | the variable itself, Xdebug's
implementation is more accurate.
| | 01:37 | This is useful when I'm not sure
if the variable is passed by reference,
| | 01:40 | especially when there is a long chain
containing the same variable.
| | 01:44 | In PHP, references allow variable content
to be accessed by different names.
| | 01:49 | Unlike Z pointers, they're
not actually memory addresses;
| | 01:52 | instead references are symbol table aliases.
| | 01:55 | Xdebug_debug_zval displays the reference count,
which is the number of aliases
| | 02:01 | a particular variable has in the symbol table.
| | 02:03 | For example, when a variable is passed
between functions, the count will increase.
| | 02:09 | The is_ref flag indicates the
variable was passed by reference.
| | 02:13 | So if I were to alter the content
of that variable, the original variable
| | 02:17 | would also be affected.
| | 02:19 | To demonstrate this, I'm going back to the IDE.
| | 02:22 | In function A, use xdebug_debug_zval
to display information about arg,
| | 02:30 | then pass arg to function B. In function B, add an
ampersand in front of arg to pass by reference.
| | 02:40 | Next, I'm going to use xdebug_debug_zval,
on arg again before the call to function D.
| | 02:47 | Then, in function D, add the same line
to debug the variable without a reference.
| | 02:55 | Save, then return to the browser and refresh.
| | 03:01 | The first pram indicates two reference counts.
| | 03:04 | The second shows three reference counts and
that the variable was passed by reference.
| | 03:09 | Remember, the reference count is the count
of aliases a particular variable
| | 03:14 | has in the symbol table.
| | 03:15 | Another useful function allows the display
of all the declared variables
| | 03:19 | that are in the current scope.
| | 03:20 | However, it requires a little extra configuration
to collect variables during execution.
| | 03:25 | Go to the terminal and edit php.ini again,
press Esc+/ to navigate
| | 03:32 | to the end of the file and add the following,
xdebug.collect_vars = 1.
| | 03:41 | While I'm at it, I will also configure
the stack traces to show the contents
| | 03:44 | of local variables as well.
| | 03:46 | xdebug.show_local_vars = 1.
| | 03:53 | Finally, I will also tell Xdebug to
keep track of the names and the contents
| | 03:57 | of parameters for each step of the call stack.
| | 04:00 | This will cause a performance hit in
very large scripts but for now its fine.
| | 04:04 | xdebug.collect_params = 4,
exit and save and restart the Web server.
| | 04:15 | Return to the IDE and remove the calls
to xdebug_debug_zval and the debug backtraces
| | 04:25 | in function D and notify shutdown.
| | 04:32 | In function D, add the following to the top,
declared = variable, then var_dump
| | 04:40 | (xdebug get_declared_vars).
| | 04:47 | Save, then, go back to the browser and refresh.
| | 04:52 | The names of each of the variables in
the current scope are shown as strings
| | 04:55 | in an array both arg and declared.
| | 04:57 | And the contents are not shown
by Xdebug yet declared vars.
| | 05:02 | Additionally, information about the
individual arguments and function calls
| | 05:06 | are shown in the stack traces.
| | 05:07 | While it can be useful to get
this information by explicitly adding
| | 05:11 | xdebug_get_declared_vars,
and other statements, is this the only way?
| | 05:16 | What about pausing script execution?
| | 05:19 | Xdebug remote debugging supports this functionality.
| | Collapse this transcript |
| Exploring remote debugging principles| 00:00 | One of Xdebug's features is the ability
to remotely debug script execution.
| | 00:05 | In particular, it provides introspection
into data structures and allows code execution
| | 00:09 | to be stepped through for debugging.
| | 00:12 | Remote debugging is turned off by default,
so I will demonstrate how to turn it on.
| | 00:17 | Remember, this is for development purposes.
| | 00:20 | Do not use remote debugging
in production environments.
| | 00:23 | Before I jump into configuration and
demonstration, I will describe the workflow
| | 00:27 | where Xdebug interacts with the remote debugger.
| | 00:30 | This will provide context and highlight
areas that should be investigated
| | 00:34 | if there are connection problems.
| | 00:36 | First, the Web server listens for request,
same as usual.
| | 00:39 | However, when a request is made,
Xdebug will attempt to connect to the debugger
| | 00:44 | on the remote IP from the headers via port 9000.
| | 00:48 | If found the IDE will give instructions
on where to pause and when to continue.
| | 00:53 | Whenever Xdebug is paused, it will provide
information back to the debugger,
| | 00:57 | so this is a two-way communication.
| | 01:00 | Once the debugger says Xdebug can continue,
the http response is updated.
| | 01:06 | This loop will continue
until script execution is complete
| | 01:09 | or Xdebug is commanded to halt.
| | 01:11 | Now that I described the workflow
and the moving parts, the configuration and use
| | 01:15 | should make a bit more sense.
| | 01:17 | Switching to the terminal, edit php.ini again.
Navigate to the end of the file.
| | 01:26 | First, I will enable remote debugging
xdebug remote_enable = 1.
| | 01:35 | Then, I will tell Xdebug to attempt
to connect to a debugger
| | 01:39 | if a remote debugging session has started
via the IP from the headers.
| | 01:42 | There are strategies for multiple users
on one server but they're
| | 01:46 | out of scope for this course.
| | 01:47 | I'm focusing on one developer for now.
| | 01:48 | Xdebug.remote_connect back = 1,
exit and save.
| | 01:57 | Restart the server.
| | 02:00 | Now that the server is restarted, I need
to make sure that two-way communication
| | 02:04 | is possible on the remote debug port 9000.
| | 02:06 | In my case, since I'm using a virtualized
development server, I'm confident
| | 02:11 | that there is no port conflict
so I do not need to forward any ports.
| | 02:15 | If there was a remote server, then
I would need to make sure that the firewall,
| | 02:19 | if any, was configured correctly
to allow the bidirectional traffic.
| | 02:23 | Additionally, if there was a router
between you and the remote server,
| | 02:27 | the port would have to be forwarded.
| | 02:29 | Before I demonstrate how to use remote debugging,
I'll quickly describe
| | 02:32 | the practical workflow within the IDE.
| | 02:35 | This applies to NetBeans specifically
but is very similar to other IDEs as well.
| | 02:40 | First, I'll set the breakpoints,
which are the places within script execution
| | 02:44 | where Xdebug will pause
and send debugging information.
| | 02:47 | Breakpoints set within the IDE are
on a specific line of code and are simply
| | 02:52 | on or off with no logic.
| | 02:54 | If I want to use logic, I can add a call
to function Xdebug break,
| | 02:58 | which will have the same effect.
| | 03:00 | Next, I'll tell the IDE to debug the project.
| | 03:03 | This will launch the browser,
opening the project URL
| | 03:07 | with an additional parameter in the URL
that sets a cookie and tells Xdebug
| | 03:11 | that this is a debugging session.
| | 03:13 | This script will execute until Xdebug
reaches the breakpoint, at which point
| | 03:17 | Xdebug will send debugging
information back to the IDE.
| | 03:21 | From the IDE, I will tell Xdebug
to go on to the next step, which is either
| | 03:25 | another breakpoint or the end of the script.
| | 03:27 | With that context, I'll demonstrate how to
remotely debug with NetBeans and Xdebug.
| | Collapse this transcript |
| Xdebug remote debugging with NetBeans| 00:00 | NetBeans 7.2 has Xdebug support built into it,
but some minor configuration is needed first.
| | 00:06 | I'll need to change the default
debugging configuration.
| | 00:09 | Edit the NetBeans preferences,
click PHP, then Debugging.
| | 00:16 | Uncheck Stop at the First Line,
which would pause execution when it reaches
| | 00:20 | the first line, which I find
distracting and I always skip. Click OK.
| | 00:25 | Right-click the Project and go to Properties.
| | 00:30 | Under Run Configuration, specify the PROJECT URL.
| | 00:34 | In my case it's sandbox.dev.8080, click OK.
| | 00:42 | NetBeans is now configured to work as a debugger.
| | 00:45 | I've described the NetBeans debugging workflow,
now I'll demonstrate it.
| | 00:49 | For NetBeans, I'm going to set a breakpoint.
| | 00:51 | Scroll down to the var dump xdebug_get_declared vars
and left-click
| | 00:57 | just to the left of the line number.
| | 00:59 | The entire line will be highlighted in red.
| | 01:02 | This means a breakpoint will be set,
so Xdebug will pause execution on that line.
| | 01:07 | At the top of the toolbar,
click the green arrow with a breakpoint icon
| | 01:11 | to start the debugger and launch the browser.
| | 01:16 | Notice that the browser is still loading.
| | 01:18 | The session isn't complete yet
as Xdebug is paused at the breakpoint.
| | 01:22 | Go back to NetBeans, at the bottom,
debugging information is now shown.
| | 01:27 | The first new tab is variables, which will
show all the superglobals like Cookie and Server
| | 01:32 | in addition to all the variables within
the current scope of the breakpoint.
| | 01:38 | The contents of each variable are shown.
| | 01:41 | I can see that declared is
set to the string variable.
| | 01:44 | I also have the ability to edit the variables,
which is very useful.
| | 01:48 | Double-click the variable value to edit
in place or click in the three dots
| | 01:53 | to the right to edit in a pop up.
| | 01:55 | Change the value to "edited" and click OK.
| | 02:01 | The next tab, Call Stack, shows the call stack
ordered by the most recent at the top.
| | 02:06 | I can see that index required the demo file,
then the function 'a' was called,
| | 02:10 | followed by 'b' then 'd.' I can double-click
on any of these items
| | 02:15 | to jump to that place and code.
| | 02:18 | The line of code is highlighted as the
Call Stack line, and if I hover over
| | 02:22 | the symbol on the left, the hovered text
will say Call Stack Line.
| | 02:26 | The final debugging tab, Breakpoints,
is a list of all the breakpoints
| | 02:31 | that have been set and they can be
toggled or disabled in this interface.
| | 02:35 | Now that I've edited the value of the variable,
I'm going to continue the execution.
| | 02:40 | Up on the top, there is a green Play button;
click it to Continue.
| | 02:45 | There is also a keyboard shortcut, F5,
which will do the same thing.
| | 02:49 | The script execution will complete
and switching back to the browser,
| | 02:53 | I can see that the entire page is loaded.
| | 02:55 | The contents of the edited variable are shown.
| | 02:58 | When I reload the page,
the debugging process is started again
| | 03:03 | and the execution is paused.
| | 03:05 | If I navigate to just index.php,
the cookie set still tells Xdebug to pause.
| | 03:12 | To stop the debugging session, return to
NetBeans and click the big red stop button.
| | 03:19 | This will open a new browser window with a
different parameter, and a short message;
| | 03:22 | DEBUG SESSION ENDED will be shown.
| | 03:25 | In the next segment, I'll show how Xdebug
can be used to profile performance
| | 03:29 | to find bottlenecks and scripts.
| | Collapse this transcript |
| Profiling performance to find bottlenecks| 00:00 | One of Xdebug's features is a profiler,
which analyzes program execution
| | 00:04 | to measure memory usage, duration,
and frequency of function calls.
| | 00:09 | The profiler generates files
that can be analyzed with third-party tools,
| | 00:14 | known as cache grind, which I will demonstrate.
| | 00:16 | Similar to other techniques that I've
demonstrated, profiling is susceptible
| | 00:20 | to the observer effect, as it has an
impact on the speed of program execution.
| | 00:25 | Therefore, Xdebug leaves profiling off by default.
| | 00:28 | I'm going to selectively enable the profiler.
| | 00:31 | Meaning, instead of recording every single page,
I will need to pass an additional header
| | 00:35 | or cookie to manually trigger it.
| | 00:38 | This way I don't have to sort through
all the generated files
| | 00:41 | to find the particular one I'm interested in.
| | 00:43 | By default, Xdebug will write
to/tmp/cashgrind.out.processID.
| | 00:51 | Switching to the terminal,
I'm going to edit the PHP configuration.
| | 00:55 | sudo nano -w /etc/php5/apache2/php.ini.
| | 01:04 | Skipping to the end of the file,
I'm going to add one line that will allow
| | 01:08 | Xdebug's profiler to be manually triggered.
| | 01:10 | xdebug.profiler_enable_trigger = 1.
| | 01:19 | Exit and Save then Restart the Web server,
sudo /etc/init.d/apache2 restart.
| | 01:28 | Now that Xdebug is ready to profile,
I'm going to demonstrate how profiling
| | 01:31 | can find a bottleneck.
| | 01:32 | Go to the IDE and scroll to the bottom
and add two new functions.
| | 01:38 | The first will be to simulate slow execution
of a function by counting to 100,000.
| | 01:44 | Slow execution, so function slow
for ($i = 0; $i < 100000; $i++)
| | 01:58 | and then do nothing.
| | 02:00 | The second will be to simulate
an even slower function,
| | 02:05 | slow execution even more.
| | 02:09 | Function slower, usleep(50000).
| | 02:17 | Before the function call to a,
add calls to the new functions.
| | 02:21 | I'm going to loop the execution of slow
in order to simulate a real-world problem,
| | 02:25 | where slow function gets called a lot of times.
| | 02:28 | for ($i=0; $i<50; $i++) and we'll call slow
and then we'll call slower once.
| | 02:41 | Returning to the browser, I'm going
to manually profile page execution.
| | 02:46 | Navigate to the root, but this time
we'll specify index.php and pass
| | 02:51 | the parameter XDEBUG_PROFILE = 1 in the URL.
| | 02:57 | Script execution takes quite a bit longer now
and the stack trace
| | 03:01 | from the errors highlights that.
| | 03:03 | Now to analyze the profile. Included in
the Exercise Files, is a copy of webgrind,
| | 03:07 | a utility for analyzing profiler results.
| | 03:11 | Navigate to sandbox.dev port 8080/webgrind.
| | 03:18 | At the top select Show 100% of the Auto (newest)
in microseconds and click update.
| | 03:25 | A large table is shown.
| | 03:28 | On the left is an icon showing the type of call.
| | 03:31 | Hovering over the image
will indicate what kind it is.
| | 03:35 | In this case, there are three procedural calls
and the rest are internal.
| | 03:40 | The next column is the Function column,
which displays the function in question.
| | 03:44 | If I click the arrow next to the Function,
it will show where the function was called from
| | 03:48 | and provide additional context.
| | 03:52 | To the right is a link to a formatted view
of the code in question.
| | 03:56 | As this is a development site not visible
to the public, it's not a security risk,
| | 04:00 | but do consider the audience
before using this utility.
| | 04:03 | Invocation Count is the number of times
the Function has been evoked.
| | 04:08 | Total Self Cost is the aggregate cost
in milliseconds for the function itself,
| | 04:13 | while Total Inclusive Cost is how long
the function takes to execute,
| | 04:17 | including everything that was executed in it.
| | 04:19 | There is an additional button,
Show Call Graph, which uses Python
| | 04:23 | in an additional library for generating
a nice flowchart of script execution.
| | 04:26 | However, this requires a lot more
configuration and installation,
| | 04:30 | so I will not cover it within this course.
| | 04:32 | By default, webgrind sorts by Total Self Cost.
| | 04:35 | This indicates that the function slow
is the slowest.
| | 04:39 | However, this isn't useful because comparing
to the PHP function usleep,
| | 04:43 | it's saying that it has a high self cost as well
and the slower function,
| | 04:48 | which we know is slow,
has a Total Self Cost of 48.
| | 04:52 | Since I know that the PHP core function
is not the problem, I'm going to click
| | 04:56 | Hide PHP functions and press update.
| | 04:59 | Now, only the functions I wrote are shown.
| | 05:02 | Notice that the Total Self Cost of slow
is the highest along with the Invocation Count.
| | 05:07 | Compare this to slower,
which has a very tiny Self Cost.
| | 05:10 | What this indicates is that something in slow
is causing a problem, as the Self Cost
| | 05:14 | is identical to the Inclusive Cost.
| | 05:17 | In contrast, the Self Cost for slower
is basically nothing,
| | 05:21 | while the Inclusive Cost is very high.
| | 05:23 | This indicates that something that slower
is calling is actually slowing down execution,
| | 05:27 | not the slower function itself.
| | 05:31 | By comparing Invocation Counts and Costs,
I can make a determination
| | 05:35 | about the greatest return of investment
of my optimizing efforts.
| | 05:39 | In particular, if something is invoked a lot
and has nearly identical Self and Inclusive Cost,
| | 05:43 | it's a good candidate for optimization.
| | 05:47 | Fortunately, in this case,
I know that slow and slower are the problem
| | 05:51 | and serve no functional purpose,
so the optimization step will be their elimination.
| | 05:56 | In this chapter, I've introduced
Xdebug, the debugging PHP extension.
| | 06:01 | I first discussed what Xdebug is
and how it can be used.
| | 06:05 | Then I demonstrated how to install Xdebug
and gave links to additional documentation
| | 06:09 | if there were problems.
| | 06:11 | I showed how Xdebug changes how Variables
are displayed and how Call Stacks can be shown.
| | 06:17 | Next, I discussed the Xdebug remote workflow,
configuring and performing
| | 06:21 | remote debugging with NetBeans.
| | 06:23 | Finally, I demonstrated how Xdebug can be used
to profile script execution
| | 06:28 | and how to analyze the results.
| | 06:30 | In the next chapter, I'll turn to Web browsers
and how they can be leveraged
| | 06:34 | as effective debugging tools.
| | Collapse this transcript |
|
|
3. Debugging from the BrowserExtending Firefox with Firebug and FirePHP| 00:00 | When debugging interactions,
and especially Ajax interactions,
| | 00:04 | the importance of the use of the browser
as a debugging tool becomes clear.
| | 00:07 | Most modern browsers come equipped
with development tools that provide
| | 00:11 | HTML and Style Inspection, JavaScript profiling
and debugging and a JavaScript console.
| | 00:16 | Mozilla Firefox lacks many
of these tools out-of-the-box.
| | 00:20 | Instead, a comprehensive suite of Web
development tools can be found in Firebug,
| | 00:24 | a free and open-source extension
that includes among other things,
| | 00:28 | HTML and Style Inspection and a JavaScript
debugger, originally created in 2006
| | 00:33 | by one of the Firefox creators.
| | 00:35 | Firebug provides a wide array of functionality
that many Web developers
| | 00:38 | have become accustomed to
in implementations of the WebKit DevTools
| | 00:42 | and Chrome Developer Tools.
| | 00:44 | All these tools are client-side only.
| | 00:46 | Meaning, they are fantastic for
debugging things locally,
| | 00:49 | but have no introspection
into what's happening on the server.
| | 00:52 | This means PHP, which runs exclusively
on the server, doesn't normally
| | 00:56 | have a mechanism for communicating
with the local browser debugger.
| | 00:59 | Throughout this chapter, I will demonstrate
several debugging consoles
| | 01:03 | that interact with PHP and a standalone
debugging library that renders as an overlay.
| | 01:08 | To save time, I have installed and arranged
each server-side tool in the Exercise Files
| | 01:12 | and have provided a centralized array
in index.php that can be used
| | 01:17 | to selectively enable and disable them.
| | 01:20 | I will describe each tool's integration,
so it can be use as a template
| | 01:24 | for other installations.
| | 01:25 | I'll start with Firebug and FirePHP.
| | 01:28 | FirePHP allows logging to the Firebug console
with a PHP function call,
| | 01:33 | including status messages and object contents.
| | 01:36 | There are several distinct components
for the solution stack:
| | 01:38 | Firefox, the Web browser; Firebug, the extension
that provides the debugging functionality;
| | 01:43 | FirePHP, the extension that interacts
with the server;
| | 01:47 | and FirePHPCore, the PHP library
that sends information via headers
| | 01:52 | to the extension from the server.
| | 01:54 | I'll start by opening my Firefox browser.
| | 01:57 | First, I'll install Firebug.
| | 01:59 | Navigate to getfirebug.com,
then click Install Firebug.
| | 02:05 | I want Firebug 1.10.6 for Firefox 16.
| | 02:10 | Click download, then add to Firefox.
Click Install Now.
| | 02:15 | Click OK and close the new tab.
| | 02:20 | Next, I'll install the FirePHP extension.
| | 02:23 | Navigate to firephp.org.
| | 02:28 | Select FirePHP Extension for Firefox 8 and above,
and Firebug 1.9 and above.
| | 02:33 | Click the link for the Stable Channel,
click Continue to Download
| | 02:39 | and Accept the new BSD License and Install.
| | 02:44 | Now, that both the extensions are installed,
restart Firefox.
| | 02:47 | Navigate to the Exercise Files,
http//sandbox.dev.8080.
| | 02:55 | Click the Firebug icon
in the upper right corner.
| | 02:59 | You can safely close this one-time tab.
| | 03:03 | Verify that both Console is enabled
and Net is enabled.
| | 03:10 | The FirePHP Library Installation is straightforward,
just download and include a PHP library
| | 03:14 | at the top of the script.
| | 03:17 | To save time, I've installed the FirePHP Library
in the provided Exercise Files.
| | 03:22 | Switching to the IDE, open index.php and
navigate the tools array at the top of the script.
| | 03:29 | Set the key firephp to True.
| | 03:32 | Scrolling down, all this does is require
the firephp library and start output buffering
| | 03:37 | as FirePHPCore sends information
in the headers and I want to make sure
| | 03:41 | that no content gets sent
before FirePHPCore gets a chance to work.
| | 03:46 | The FirePHPCore library itself has been
organized into the subfolder, FirePHPCore.
| | 03:51 | Now, that FirePHP has been enabled
and configured, it's time to use it.
| | 03:56 | Remember to save index.php before continuing.
| | 03:59 | I'm going to make a quick backup of demo.php
as I'm going to demonstrate
| | 04:03 | different techniques later
and I want the same starting point.
| | 04:05 | So, I'm going to right-click on demo and go to
Copy and then Paste back in the Source Files.
| | 04:12 | I'm going to scroll to the top of the script,
and I'll start by getting
| | 04:16 | a FirePHP instance using the built in
singleton pattern after the ini_sets.
| | 04:20 | Meaning that there will only be one
FirePHP instance as long as I use
| | 04:24 | the static function to get it.
| | 04:25 | Get FirePHP instance and then
$firephp = FirePHP::get Instance (TRUE).
| | 04:39 | As FirePHP is a logger, let's log some actions.
| | 04:42 | Following the shutdown function registration,
I'm going to add log entry,
| | 04:45 | $firephp, I'll call the function log,
which takes a string
| | 04:52 | Registered notify_shutdown.
| | 04:56 | This will show up in the Firebug console log.
| | 04:59 | Log can also take a second argument,
a label to be shown in the interface.
| | 05:02 | Scroll down to the for loop and create a log entry,
this time with the label performance,
| | 05:07 | $firephp->log('Executing slow loop.')
and we'll add up the label Performance.
| | 05:17 | Save and then return to Firefox,
click on Console and reload the page.
| | 05:22 | The Console shows two log entries.
| | 05:25 | The second log entry is pre-appended
with the label.
| | 05:28 | Hovering over each of the log entries,
I can see exactly what line in what file
| | 05:32 | the log entry was triggered in.
| | 05:34 | Firebug also supports three
basic error levels as well.
| | 05:38 | Switching back to the IDE, navigate to
function d where the errors are triggered.
| | 05:43 | As I'm currently in the function scope,
get the singleton instance of FirePHP,
| | 05:48 | $firephp = FirePHP::getInstance(TRUE)
| | 05:55 | Before the notice, I'm going to use
a different function, as this system
| | 05:59 | is compatible with Firebug, a JavaScript tool,
| | 06:01 | there is no PHP notice support.
| | 06:03 | Instead, I'll use info,
$firephp->info('Triggered notice.')
| | 06:10 | Do the same for warning, $firephp,
which is just named warn, 'Triggered warning.'
| | 06:18 | Finally, error which is just error,
$firephp->error('Triggered error').
| | 06:27 | Return to the browser and refresh.
| | 06:30 | Notice that when I trigger an error,
an error count is showed in the Firebug icon,
| | 06:34 | which is an excellent visual indicator to developers.
| | 06:37 | The triggered notice, warning and error
are shown with different icons
| | 06:42 | and each of them can be hovered over
to tell you the file and line number.
| | 06:45 | Switching back to the IDE, I'm going to show you
two more tools available in Firebug.
| | 06:50 | Instead of var_dump, I can also
log any PHP structure.
| | 06:54 | Replace the var_dump Xdebug_get_declared vars
with the firephp log.
| | 07:01 | $firephp, log, xdebug, get declared vars,
and then we'll followup
| | 07:06 | with an optional label,
xdebug_get_declared_vars.
| | 07:11 | We can remove the var_dump.
| | 07:13 | Additionally, FirePHP supports stack traces
using the trace function, $firephp trace,
| | 07:17 | which we'll give a label just as Trace.
| | 07:23 | Save, then return to the browser and refresh.
| | 07:25 | I can see the Xdebug_get_declared_vars
in the Console, but I can't see all of it.
| | 07:30 | Click on the array,
and a Variable Viewer will pop up.
| | 07:33 | This is much more useful. Click Close.
| | 07:37 | The Trace is displayed as well, click on it
to see the Stack Trace, which is fairly simplified.
| | 07:42 | The combination of FirePHP and Firebug
is a powerful one,
| | 07:46 | but requires a particular browser,
however, there are other alternatives.
| | Collapse this transcript |
| Integrating ChromePHP| 00:00 | ChromePHP is a console logging extension
for Google Chrome. It's similar to FirePHP,
| | 00:05 | but the feature set is a little bit more limited,
including a lack of stack traces.
| | 00:09 | While it's not as robust,
I can demonstrate how to make it useful.
| | 00:13 | To use ChromePHP, there are a number
of components that need to be assembled.
| | 00:17 | First, the Chrome Browser, which hosts
the ChromePHP extension. Finally
| | 00:22 | the ChromePHP class, which resides on the server
and sends the headers to be logged.
| | 00:27 | Switching to the Chrome Browser,
navigate to http://www.chromephp.com.
| | 00:33 | Click the Download link on Step 1
to install the extension.
| | 00:37 | Click ADD TO CHROME and Add.
| | 00:40 | You can close the window now for the
Chrome Web Store, then switch
| | 00:44 | to the IDE and open index.php.
| | 00:47 | I have already installed the
ChromePHP Library to save time,
| | 00:51 | but configuration is required.
| | 00:52 | Make sure FirePHP is set to False and
then set ChromePHP to True. Save index.php.
| | 01:01 | The only installation step is shown below,
which is to include the library,
| | 01:05 | and start output buffering.
| | 01:07 | Copy the contents of the backup demo
into the demo file
| | 01:13 | to remove all the incompatible
PHP debugging information.
| | 01:16 | Scrolling to the top,
instead of the singleton instance,
| | 01:20 | ChromePHP just uses static methods.
| | 01:21 | I'll start by logging the registration
of the shutdown function.
| | 01:25 | Just after the registration, add the following.
| | 01:27 | ChromePhp::log('Registering shutdown function.')
Save, then, return to Chrome.
| | 01:38 | Navigate to the exercise files, then,
click the ChromePHP icon in the upper-right.
| | 01:46 | Reload the page and open up the Console.
| | 01:51 | The message Registering shutdown function
is shown, but no context is shown
| | 01:55 | even if I hover over the message.
| | 01:57 | Right-click on the ChromePHP icon
and go to Options.
| | 02:01 | I'm going to check Show line numbers
and click Save Changes.
| | 02:07 | Going back to the debugging PHP window,
I'll reload the page.
| | 02:11 | This time the file and line number are shown,
but on a separate line.
| | 02:15 | While this is helpful,
this is a wasteful way of doing it.
| | 02:18 | Go back to the ChromePHP Extension Settings
and disable show line numbers then Save Changes.
| | 02:23 | Returning to the IDE, I'm going to make
the message a bit more verbose.
| | 02:27 | Unlike FirePHP, ChromePHP log functions
take the label first, then the message.
| | 02:33 | Using magic constants, I'll provide context.
| | 02:35 | So, go to log(_File_ . concatenate, the semicolon,
then the line and comma,
| | 02:46 | and then the Registering shutdown function.
| | 02:48 | Save, then return to Chrome and Reload.
| | 02:52 | This time the file and line are shown in line.
| | 02:55 | This method is more compact,
but requires additional code.
| | 02:58 | Returning to the IDE, go to function d.
| | 03:03 | Replace the var_dump of
xdebug_get_declared_vars with a log.
| | 03:06 | Remember, label first, then content.
| | 03:09 | So ChromePhp, log, then we'll give the label
xdebug_get_declared_vars
| | 03:18 | and then the function call itself.
| | 03:20 | A neat feature of ChromePHP is the ability
to group a series of log messages.
| | 03:24 | I'm going to log a backtrace and I'll start
by defining the name of the group
| | 03:28 | using Group Collapsed.
| | 03:30 | ChromePhp, groupCollapsed and
we'll give it a name, backtrace.
| | 03:35 | Next, log the debug a backtrace array.
So ChromePhp, log, debug_backtrace.
| | 03:44 | Finally, ends the group.
| | 03:46 | ChromePhp, groupEnd.
| | 03:51 | ChromePHP supports three error levels as well.
| | 03:54 | Before the notice and the same as FirePHP, use info.
| | 03:58 | ChromePhp, info, Triggered notice.
| | 04:04 | Then before the warning, a warn,
ChromePhp, warn, Triggered warning,
| | 04:12 | and finally, an error.
| | 04:13 | ChromePhp, error, Triggered error,
Save, then, return to Chrome and Reload.
| | 04:21 | The contents of xdebug_declared_vars
are shown in line, but can't be clicked on.
| | 04:27 | Backtrace can be opened and debugged
like a JavaScript object.
| | 04:34 | The Triggered notice shows the same as a log message.
| | 04:37 | The warning and error are displayed
with appropriate icons, but the Triggered error
| | 04:41 | is treated the same as a JavaScript error.
| | 04:43 | ChromePHP is a good tool,
but does suffer from some limitations.
| | 04:47 | What if I wanted to debug without
any extensions with any browser?
| | Collapse this transcript |
| Using PHP_Debug to debug without a console| 00:00 | PHP Debug is an open source, debugging library
written in PHP that resides
| | 00:05 | completely server-side, so no particular
browser or extensions are needed.
| | 00:09 | Some of its features include:
| | 00:10 | displaying the server configuration
and global variables by default;
| | 00:14 | stack traces to provide context about
program execution; variable dumping;
| | 00:19 | multiple rendering options, so either the
results can be floated as a DIV or appended
| | 00:23 | as an HTML table at the end of execution;
and PHP error-handling replacement.
| | 00:28 | So instead of Xdebug other debugging tools,
PHP_Debug can provide contexts upon errors.
| | 00:34 | PHP_Debug can be installed via PEAR.
| | 00:37 | Additionally, PHP_Debug uses another library.
| | 00:39 | Text-Highlighter also available via PEAR.
| | 00:42 | However, PHP_Debug has some hard coded
configuration within the library itself,
| | 00:45 | and as of this writing, Text_Highlighter
is no longer maintained
| | 00:50 | and contains a strict error that I fixed.
| | 00:52 | Therefore, I just included the libraries
in the PHP_Debug directory
| | 00:56 | to simplify installation.
| | 00:57 | Opening the IDE, I'm going to restore
demo.php to the state it was
| | 01:02 | at the beginning of the chapter.
| | 01:04 | So I'm going to just copy and paste.
| | 01:07 | Next, open index.php, and disable ChromePHP
and enable PHP_Debug by setting it to True.
| | 01:17 | Integration happens in several places.
| | 01:19 | The setup includes creating an array
describing relative paths
| | 01:23 | and some other configuration information.
Then the included path is updated
| | 01:27 | to include the path to the libraries.
| | 01:29 | And finally, the require_once to the PHP folder.
| | 01:32 | Unfortunately, PHP_Debug does not use a
singleton pattern, so as a workaround,
| | 01:36 | I created a globalvariable, which I do
not consider to be a best practice.
| | 01:40 | Scrolling down, JavaScript and CSS is also added
and at the bottom of the script
| | 01:46 | the output of PHP_Debug is rendered.
| | 01:49 | This is a lot more intrusive than the
other debugging libraries,
| | 01:52 | but there is a method to the madness.
| | 01:53 | Navigate to PHP_Debug> Text>Highlighter.php.
| | 01:58 | On line 199, I changed the function factory
to static to avoid a strict error.
| | 02:04 | There is one configuration change that is needed.
| | 02:07 | Navigate to PHP_Debug_ShowSource.php.
| | 02:11 | On line 24, there is a hard coded ALLOWED_PATH.
| | 02:15 | I understand the need of having security,
but having to edit the library
| | 02:18 | to reconfigure it is suboptimal.
| | 02:20 | Change the ALLOWED_PATH to
reflect your exercise Web root.
| | 02:24 | Make sure you save and go to
the browser and reload the page.
| | 02:29 | Notice that the page looks a lot cleaner.
| | 02:31 | All of the Xdebug error handling has been
hidden along with the shotdown function.
| | 02:35 | There is also a new toolbar in the upper-right.
| | 02:38 | Click vars & config.
| | 02:39 | This will show a number of superglobals,
PHP Configuration and every file that
| | 02:44 | was loaded with a link to view the source.
| | 02:47 | Going back, click on logs & messages.
| | 02:51 | The Triggered PHP errors are shown with context.
| | 02:55 | Clicking on the watch, execution time
is displayed, broken into PHP and SQL.
| | 03:01 | While the implementation is decidedly imperfect,
PHP_Debug is a powerful tool.
| | 03:06 | Opening the IDE, I will
demonstrate how to perform
| | 03:10 | some of PHP_Debugs logging facilities.
| | 03:11 | Open the demo file.
| | 03:13 | After the ini_sets, get the global
PHP_Debug object, global $PHP_Debug.
| | 03:22 | Then, use the add function
for the shutdown function,
| | 03:26 | which will add the message to the log.
| | 03:27 | $PHP_Debug->add('Registering shutdown function.').
| | 03:33 | Next, I'll demonstrate how to dump a variable
by replacing the var_dump in function d.
| | 03:36 | As the scope is within the function,
I'll need to get the global objects again,
| | 03:41 | global $PHP_Debug.
| | 03:44 | Then, PHP_Debug uses the function dump
as a replacement to var_dump.
| | 03:49 | So $PHP_Debug->dump.
| | 03:53 | Finally, I will demonstrate how to
add benchmarks to log execution time.
| | 03:57 | Scroll down to after the function d declaration.
| | 04:00 | I'm going to benchmark the slow function loop.
| | 04:03 | The add function returns an
objects that offers additional controls,
| | 04:07 | such as setting to start and end times.
| | 04:09 | So we'll say $debug_line=$PHP_Debug->
| | 04:15 | add('Slow loop benchmark') and then
| | 04:21 | $debug_line->setStartTime.
| | 04:22 | Then after the loop,
$debug_line->setEndTime.
| | 04:28 | Save, then return to the browser and refresh.
| | 04:34 | For the first time since I started, the page
contains no errors or debugging information
| | 04:38 | and only displays the message
that we set after the fatal error.
| | 04:42 | Clicking on logs & messages, I can see the
slow loop benchmark has a time next to it,
| | 04:47 | 788 milliseconds, and the variable dump
is displayed as well.
| | 04:52 | If I click on the watch, the slow loop benchmark
has been broken out separately.
| | 04:56 | Throughout this chapter I've explored
how to debug from the browser.
| | 05:00 | In particular, I've demonstrated how to
extend Firefox with Firebug and FirePHP;
| | 05:05 | How Chrome PHP can provide similar
logging functionality to Chrome;
| | 05:09 | and finally, how to eliminate the need for
browser extensions by using PHP_Debug
| | 05:13 | to debug without a console.
| | 05:15 | Now that I've discussed a wide variety
of server side and client side tools,
| | 05:19 | I'll describe a number of tried and true
debugging best practices
| | 05:22 | and offer ideas of where to go from here.
| | Collapse this transcript |
|
|
ConclusionBest practices| 00:00 | As a programmer, I'm very aware that
for every problem there are multiple solutions.
| | 00:05 | With that in mind, here are a number
of best practices that I recommend
| | 00:09 | for building optimal scalable solutions.
| | 00:11 | One of the challenges faced as a developer
is finding exactly where the bug is.
| | 00:16 | Using debugging break points,
there is a technique known as binary split.
| | 00:20 | In short, set a breakpoint
halfway through the program.
| | 00:23 | If the problem does not occur, set a second
breakpoint halfway through the second half.
| | 00:28 | Otherwise, put the second breakpoint
in the first half.
| | 00:31 | Keep putting breakpoints in the middle
of the halves to narrow down where the
| | 00:34 | problem is occurring.
| | 00:35 | Using this technique, I can limit the search
area of a thousand line program in ten steps.
| | 00:41 | Being able to track changes over time is essential
to code organization and accountability.
| | 00:46 | It's not just about blaming someone;
| | 00:48 | it's about determining what changed,
when and why.
| | 00:51 | Regardless of the size of the project,
even if there's only one person working on a project,
| | 00:55 | or if there are multiple teams collaborating,
use version control.
| | 00:59 | For more information, I recommend
Fundamentals of Software Version Control
| | 01:03 | with Michael Lehman, here in the
lynda.com Online Training Library.
| | 01:08 | When working with a team,
there are going to be bugs.
| | 01:11 | It can be especially tempting to ignore problems
and assume that somebody else
| | 01:14 | is going to fix it. Don't wait.
| | 01:17 | Act soon or rather than later.
| | 01:18 | At the very least, document that the issue exists,
including steps to replicate in an issue tracker.
| | 01:24 | Again it's not about blame.
| | 01:26 | The goal is to improve the software.
| | 01:29 | The longer the delay in fixing,
leads to more technical debt,
| | 01:33 | which in turn makes the problem harder
and more expensive to fix.
| | 01:36 | Commenting code effectively is not complex
or difficult, but it does take discipline.
| | 01:41 | At the highest level, comments are meant
to give context or execution so that
| | 01:45 | someone reading the code, which can include
yourself, understands what's going on and why.
| | 01:50 | For example, a comment saying that
a function call will be made,
| | 01:54 | tells absolutely nothing to the observer.
Of course, it's going to be made.
| | 01:58 | On the other hand, a comment describing
the functionality of a block of code
| | 02:02 | helps give context
to understand what's going on.
| | 02:05 | Finally, don't debug in production.
It'll end in tears.
| | 02:08 | It's confusing to users at the very least
and at worst, it's a security vulnerability.
| | 02:13 | Make a private copy of the production environment,
files and database for testing
| | 02:17 | and do the debugging there.
| | Collapse this transcript |
| Where to go from here| 00:00 | This course has covered a large number
of tools and techniques, but it's by no means
| | 00:04 | the end of the road.
| | 00:06 | Execution traces also known as function traces
allow a developer to log
| | 00:10 | all function calls,
including parameters and return values.
| | 00:13 | Xdebug supports creating execution traces,
which can be parsed with the trace file parsers.
| | 00:19 | For more information
see the documentation on xdebug.org.
| | 00:24 | Instead of relying on program failures,
logging or bug reports, consider implementing
| | 00:28 | a suite of automated tests to fully exercise
individual parts of the entire program execution.
| | 00:34 | Code can be tested using a framework
such as PHPUnit where tests are written
| | 00:38 | that isolate the part of the program in
order to show that the individual parts
| | 00:42 | are operating correctly.
| | 00:43 | Browser interactions and workflows can
be scripted and tested with Selenium,
| | 00:47 | which automates browsers in PhantomJS, which runs
a functional test without requiring a browser.
| | 00:53 | These automated tests can be leveraged
when using continuous integration
| | 00:57 | where developers' code is integrated
in a centralized place in automated tests
| | 01:01 | are performed to measure the quality
of the code in system.
| | 01:04 | This facilitates manual quality assurance
practices as well and can be
| | 01:08 | essential tool when scaling up.
| | 01:10 | For a high level discussion of this approach,
see Martin Fowler's article on the subject.
| | Collapse this transcript |
| Goodbye| 00:00 | Debugging code is messy.
| | 00:02 | In every program mistakes will be made
and inevitably more problems will be created
| | 00:06 | when trying to fix the original problem.
| | 00:08 | My wife and I learned a valuable lesson
moving into a house we were fixing up.
| | 00:12 | Don't start ripping out something
unless you're prepared to deal with
| | 00:15 | whatever mess it is hiding.
| | 00:17 | Debugging can be a bit like that.
| | 00:18 | But similar to cleaning up a moldy carpet,
it's pretty much a requirement
| | 00:22 | and the consequences of not dealing
with the problem by ignoring it,
| | 00:25 | tend to be much worse than just fixing it.
| | 00:27 | I appreciate your time and I hope you
enjoyed watching this course
| | 00:31 | as much as I enjoyed writing it and recording it
while working with the team at lynda.com.
| | 00:35 | Thank you!
| | Collapse this transcript |
|
|