mirror of
https://github.com/codeguy/php-the-right-way.git
synced 2025-08-16 18:53:57 +02:00
Closes #283: Uses orginal PR as base for a recode of Errors.
This commit is contained in:
@@ -4,52 +4,114 @@ isChild: true
|
||||
|
||||
## Errors {#errors_title}
|
||||
|
||||
PHP Errors differ to Exceptions in that they, Errors can halt the execution of your script depending on the level of
|
||||
severity. Exceptions on the other hand can be caught using `try catch` statements.
|
||||
In many "exception-heavy" programming languages, whenever anything goes wrong an exception will be thrown. This is
|
||||
certainly a viable way to do things, but PHP is an "exception-light" programming language. While it does have
|
||||
exceptions and more of the core is starting to use them when working with objects, most of PHP itself will try to keep
|
||||
processing regardless of what happens, unless a fatal error happens.
|
||||
|
||||
For example:
|
||||
|
||||
{% highlight php %}
|
||||
$ php -a
|
||||
php > echo $foo;
|
||||
Notice: Undefined variable: foo in php shell code on line 1
|
||||
{% endhighlight %}
|
||||
|
||||
This is only a notice error, and PHP will happily carry on. This can be confusing for those from "exception-heavy"
|
||||
languages, because referencing a missing variable in Python for example will throw an exception:
|
||||
|
||||
{% highlight python %}
|
||||
$ python
|
||||
>>> print foo
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
NameError: name 'foo' is not defined
|
||||
{% endhighlight %}
|
||||
|
||||
The only real difference is that Python will freak out over any small thing, so that developers can be super sure any
|
||||
potential issue or edge-case is caught, whereas PHP will keep on processing unless something extreme happens, at which
|
||||
point it will throw an error and report it.
|
||||
|
||||
### Error Severity
|
||||
|
||||
PHP's built in error reporting and logging, allows for different levels of reporting via the use of Predefined
|
||||
Constants. The three main constants are `E_ERROR`, `E_NOTICE`, and `E_WARNING`.
|
||||
PHP has several levels of error severity. The three most common types of messages are errors, notices and warnings.
|
||||
These have different levels of severity; `E_ERROR`, `E_NOTICE`, and `E_WARNING`. Errors are fatal run-time errors and
|
||||
are usually caused by faults in your code and need to be fixed as they'll cause PHP to stop executing. Warnings are
|
||||
non-fatal errors, execution of the script will not be halted. Notices are advisory messages caused by code that may or
|
||||
may not cause problems during the execution of the script, execution is not halted.
|
||||
|
||||
The different levels of error severity have different meanings. The three most common types of messages are Errors,
|
||||
Notices and Warnings. Errors are fatal run-time Errors and are usually caused by faults in your code and need to be
|
||||
fixed as they'll cause execution to be halted. Warnings are non-fatal errors, execution of the script will continue
|
||||
and dependant on settings the user may or not may see the Warning message. Notices are advisory messages caused by
|
||||
code that may or may not cause problems during script execution, execution is not halted and again depending on
|
||||
settings the user may or not see the Notice message.
|
||||
|
||||
Another type of Error Message reported at compile time are `E_STRICT` messages, these messages are used to suggest
|
||||
changes to your code to help ensure best interoperability and forward compatibility for your code.
|
||||
Another type of error message reported at compile time are `E_STRICT` messages. These messages are used to suggest
|
||||
changes to your code to help ensure best interoperability and forward compatibility with upcoming versions of PHP.
|
||||
|
||||
### Changing PHP's Error Reporting Behaviour
|
||||
|
||||
Error Reporting can both be changed using PHP settings and PHP function calls. Using the built in PHP function
|
||||
`error_reporting()` you can set the level of errors for the duration of the script execution by passing one of the
|
||||
Predefined Constants. For more information on this relating to application environments check
|
||||
out the [Error Reporting][errorreport].
|
||||
Predefined Constants, meaning if you only want to see Warnings and Errors - but not Notices - then you can configure that:
|
||||
|
||||
As well as setting the level of error reporting during script execution you can also suppress Errors using the
|
||||
Error Control Operator `@` by putting this operator at the beginning an expression. The use of this operator
|
||||
is not advised and should never be used, using this operator is like admitting your code is bad and can fail over
|
||||
{% highlight php %}
|
||||
error_reporting(E_ERROR | E_WARNING | E_PARSE);
|
||||
{% endhighlight %}
|
||||
|
||||
You can also control wether or not errors are displayed to the screen (good for development) or hidden, and logged
|
||||
(good for production). For more information on this check out the [Error Reporting][errorreport] section.
|
||||
|
||||
### Inline Error Supression
|
||||
|
||||
As well as setting the level of error reporting during script execution you can also suppress specific errors from being
|
||||
displayed using the Error Control Operator `@`. You simply put this operator at the beginning an expression, and any
|
||||
error that would be caused as a direct result of the specific expression will be silenced.
|
||||
|
||||
{% highlight php %}
|
||||
echo @$foo['bar'];
|
||||
{% endhighlight %}
|
||||
|
||||
This will output `$foo['bar']` if it exists, but will simply return a null and print nothing if the variable `$foo` or
|
||||
`'bar'` key does not exist.
|
||||
|
||||
This might seem like a good idea, but due to the way PHP actually handles `@` it is incredibly unperformant, and has the
|
||||
unexpected effect of still actually logging the error anyway. If you have this code in a loop that runs 100 times in an
|
||||
instance, and you run that 1 million times, then you've got 100 million lines in your logs.
|
||||
|
||||
Instead, use the following:
|
||||
|
||||
{% highlight php %}
|
||||
echo isset($foo['bar']) ? $foo['bar'] : '';
|
||||
{% endhighlight %}
|
||||
|
||||
This will be much quicker, and save filling up your logs with junk. [SitePoint] go a step further and say you should
|
||||
[never suppress notices] with `@`.
|
||||
|
||||
One instance where error suppression might make sense is where `fopen()` fails to find a file to load. You could check
|
||||
for existence of the file before you try to load it, but if the file is deleted after the check and before the `fopen()`
|
||||
(which might sound impossible, but it can happen) then `fopen()` will return false _and_ throw an error. This is
|
||||
potentially something PHP should resolve, but is one case where error suppression might seem like the only valid
|
||||
solution.
|
||||
|
||||
* [Error Control Operators](http://php.net/manual/en/language.operators.errorcontrol.php)
|
||||
* [SitePoint](http://www.sitepoint.com/)
|
||||
* [never suppress notices](http://www.sitepoint.com/why-suppressing-notices-is-wrong/)
|
||||
|
||||
### Error Exceptions
|
||||
### ErrorException's
|
||||
|
||||
Optionally you can throw your Errors as Exceptions using the `ErrorException` class, this class extends the `Exception`
|
||||
class. This is a common practice and by passing errors off as Exceptions in development you can handle them better than
|
||||
the usual result. By passing these Errors as Exceptions and not trying to catch them in Development the hope is that
|
||||
you'll catch the Error and hopefully this will allow you to deal with the issue before it becomes a problem in a
|
||||
Production Environment.
|
||||
More information on this and details on how to use `ErrorException` with Error Handling can be found at
|
||||
PHP is perfectly capable of being an "exception-heavy" programming language, and only requires a few lines of code to
|
||||
make the switch. Basically you can throw your "errors" as "exceptions" using the `ErrorException` class, which extends the `Exception` class.
|
||||
|
||||
This is a common practice implemented by a large number of modern frameworks such as Symfony and Laravel. By default
|
||||
Laravel will display all errors as exceptions using the [Whoops!] package if the `app.debug` switch is turned on, then
|
||||
hide them if the switch is turned off.
|
||||
|
||||
By throwing errors as exceptions in development you can handle them better than the usual result, and if you see an
|
||||
exception during development you can wrap it in a catch statement with specific instructions on how to handle the situation. Each exception you catch instantly makes your application that little bit more robust.
|
||||
|
||||
More information on this and details on how to use `ErrorException` with error handling can be found at
|
||||
[ErrorException Class][errorexception].
|
||||
|
||||
* [Error Control Operators](http://php.net/manual/en/language.operators.errorcontrol.php)
|
||||
* [Predefined Constants for Error Handling](http://www.php.net/manual/en/errorfunc.constants.php)
|
||||
* [error_reporting](http://www.php.net/manual/en/function.error-reporting.php)
|
||||
* [ErrorException Class][errorexception]
|
||||
* [Reporting][errorreport]
|
||||
|
||||
[errorexception]: http://php.net/manual/en/class.errorexception.php
|
||||
[errorreport]: /#error_reporting
|
||||
[Whoops!]: http://filp.github.io/whoops/
|
||||
|
Reference in New Issue
Block a user