mirror of
https://github.com/codeguy/php-the-right-way.git
synced 2025-08-06 14:06:34 +02:00
Added some information about Exceptions.
This commit is contained in:
64
_posts/03-03-01-Exceptions.md
Normal file
64
_posts/03-03-01-Exceptions.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
isChild: true
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exceptions
|
||||||
|
|
||||||
|
Exceptions are a standard part of most popular programming languages, but they are often overlooked by PHP programmers.
|
||||||
|
Languages like Ruby are extremely Exception heavy, so whenever something goes wrong such as a HTTP request failing, or
|
||||||
|
a DB query goes wrong, or even if an image asset could not be found, Ruby (or the gems being used) will throw an
|
||||||
|
exception to the screen meaning you instantly know there is a mistake.
|
||||||
|
|
||||||
|
PHP itself is fairly lax with this, and a call to `file_get_contents()` will usually just get you a `FALSE` and a warning.
|
||||||
|
Many older PHP frameworks like CodeIgniter will just return a false, log a message to their proprietary logs and maybe
|
||||||
|
let you use a method like `$this->upload->get_error()` to see what went wrong. The problem here is that you have to go
|
||||||
|
looking for a mistake and check the docs to see what the error method is for this class, instead of having it made extremely
|
||||||
|
obvious.
|
||||||
|
|
||||||
|
Another problem is when classes automatically throw an error to the screen and exit the process. When you do this you
|
||||||
|
stop another developer from being able to dynamically handle that error. Exceptions should be throw to make a developer aware
|
||||||
|
of an error, then they can choose how to handle this. E.g:
|
||||||
|
|
||||||
|
{% highlight php %}
|
||||||
|
<?php
|
||||||
|
$email = new Fuel\Email;
|
||||||
|
$email->subject('My Subject');
|
||||||
|
$email->body('How the heck are you?');
|
||||||
|
$email->to('guy@example.com', 'Some Guy');
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$email->send();
|
||||||
|
}
|
||||||
|
catch(Fuel\Email\ValidationFailedException $e)
|
||||||
|
{
|
||||||
|
// The validation failed
|
||||||
|
}
|
||||||
|
catch(Fuel\Email\SendingFailedException $e)
|
||||||
|
{
|
||||||
|
// The driver could not send the email
|
||||||
|
}
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
### SPL Exceptions
|
||||||
|
|
||||||
|
An Exception by default has no meaning and the most common to give it meaning is by setting its name:
|
||||||
|
|
||||||
|
{% highlight php %}
|
||||||
|
<?php
|
||||||
|
class ValidationException extends Exception {}
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
This means you can add multiple catch blocks and handle different Exceptions differently. This can lead to
|
||||||
|
the creation of a <em>lot</em> of custom Exceptions, some of which could have been avoided using the SPL Exceptions
|
||||||
|
provided in the [SPL extension][splext].
|
||||||
|
|
||||||
|
If for example you use the `__call()` Magic Method and an invalid method is requested then instead of throwing a standard
|
||||||
|
Exception which is vague, or creating a custom Exception just for that, you could just `throw new BadFunctionCallException;`.
|
||||||
|
|
||||||
|
* [Read about Exceptions][exceptions]
|
||||||
|
* [Read about SPL Exceptions][splexe]
|
||||||
|
|
||||||
|
[exceptions]: http://php.net/manual/en/language.exceptions.php
|
||||||
|
[splexe]: http://php.net/manual/en/spl.exceptions.php
|
||||||
|
[splext]: /#standard_php_library
|
@@ -11,7 +11,7 @@ CLI PHP programs are powerful because you can use your app's code directly witho
|
|||||||
Try running PHP from your command line:
|
Try running PHP from your command line:
|
||||||
|
|
||||||
{% highlight bash %}
|
{% highlight bash %}
|
||||||
> php -i
|
php -i
|
||||||
{% endhighlight %}
|
{% endhighlight %}
|
||||||
|
|
||||||
The `-i` option will print your PHP configuration just like the [`phpinfo`][phpinfo] function. There are a number of other useful [command line options][cli-options], too.
|
The `-i` option will print your PHP configuration just like the [`phpinfo`][phpinfo] function. There are a number of other useful [command line options][cli-options], too.
|
||||||
@@ -19,12 +19,12 @@ The `-i` option will print your PHP configuration just like the [`phpinfo`][phpi
|
|||||||
Let's write a simple "Hello, $name" CLI program. To try it out, create a file named `hello.php`, as below.
|
Let's write a simple "Hello, $name" CLI program. To try it out, create a file named `hello.php`, as below.
|
||||||
|
|
||||||
{% highlight php %}
|
{% highlight php %}
|
||||||
<?php
|
<?php
|
||||||
if($argc != 2) {
|
if($argc != 2) {
|
||||||
die("Usage: php hello.php [name].\n");
|
die("Usage: php hello.php [name].\n");
|
||||||
}
|
}
|
||||||
$name = $argv[1];
|
$name = $argv[1];
|
||||||
echo "Hello, $name\n";
|
echo "Hello, $name\n";
|
||||||
{% endhighlight %}
|
{% endhighlight %}
|
||||||
|
|
||||||
PHP sets up two special variables based on the arguments your script is run with. [`$argc`][argc] is an integer variable containing the argument *count* and [`$argv`][argv] is an array variable containing each argument's *value*. The first argument is always the name of your PHP script file, in this case `hello.php`.
|
PHP sets up two special variables based on the arguments your script is run with. [`$argc`][argc] is an integer variable containing the argument *count* and [`$argv`][argv] is an array variable containing each argument's *value*. The first argument is always the name of your PHP script file, in this case `hello.php`.
|
||||||
@@ -32,10 +32,10 @@ PHP sets up two special variables based on the arguments your script is run with
|
|||||||
To run our script, above, from the command line:
|
To run our script, above, from the command line:
|
||||||
|
|
||||||
{% highlight bash %}
|
{% highlight bash %}
|
||||||
> php hello.php
|
php hello.php
|
||||||
Usage: php hello.php [name]
|
Usage: php hello.php [name]
|
||||||
> php hello.php world
|
php hello.php world
|
||||||
Hello, world
|
Hello, world
|
||||||
{% endhighlight %}
|
{% endhighlight %}
|
||||||
|
|
||||||
|
|
@@ -7,19 +7,19 @@ More importantly, `PDO` allows you to safely inject foreign input (e.g. IDs) int
|
|||||||
Let's assume a PHP script receives a numeric ID as a query parameter. This ID should be used to fetch a user record from a database. This is the `wrong` way to do this:
|
Let's assume a PHP script receives a numeric ID as a query parameter. This ID should be used to fetch a user record from a database. This is the `wrong` way to do this:
|
||||||
|
|
||||||
{% highlight php %}
|
{% highlight php %}
|
||||||
<?php
|
<?php
|
||||||
$pdo = new PDO('sqlite:users.db');
|
$pdo = new PDO('sqlite:users.db');
|
||||||
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
|
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
|
||||||
{% endhighlight %}
|
{% endhighlight %}
|
||||||
|
|
||||||
This is terrible code. You are inserting a raw query parameter into a SQL query. This will get you hacked in a heartbeat. Instead, you should sanitize the ID input using PDO bound parameters.
|
This is terrible code. You are inserting a raw query parameter into a SQL query. This will get you hacked in a heartbeat. Instead, you should sanitize the ID input using PDO bound parameters.
|
||||||
|
|
||||||
{% highlight php %}
|
{% highlight php %}
|
||||||
<?php
|
<?php
|
||||||
$pdo = new PDO('sqlite:users.db');
|
$pdo = new PDO('sqlite:users.db');
|
||||||
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
|
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
|
||||||
$stmt->bindParam(':id', filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT), PDO::PARAM_INT);
|
$stmt->bindParam(':id', filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT), PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
{% endhighlight %}
|
{% endhighlight %}
|
||||||
|
|
||||||
This is correct code. It uses a bound parameter on a PDO statement. This escapes the foreign input ID before it is introduced to the database preventing potential SQL injection attacks.
|
This is correct code. It uses a bound parameter on a PDO statement. This escapes the foreign input ID before it is introduced to the database preventing potential SQL injection attacks.
|
||||||
|
Reference in New Issue
Block a user