Archive for the 'introduction' Category
PHP 5 introduced a number of revolutionary features to the language that made it a much more elegant solution to many of the common programming challenges developers face. Object support went from something of a glorified after-thought to a truly compelling, modern approach. Several useful libraries and interfaces were added, and exception handling was finally given the attention many developers had longed for. Each of these are covered in their own chapters, but there were just a few other add-ons that, while too important not to cover, didn’t easily fit into more focused chapters.
Briefly, we’re going to look at three of these new features: type-hinting, objects being passed by reference, and indirect referencing.
Type hinting allows you to more precisely specify the types of arguments that should be passed into your function. In the definition, you can do something like:
function myFunction(MyClass $object) {
//do something with $object
}
This sets up a guarantee that when the function is run, $object will either be an instance of “MyClass”, an instance of a child class of MyClass type, or an instance of a class that implements an interface called MyClass. And this might be really important. Having it specified this way in the function definition will also ensure that anyone working on your code later will know that. In addition to class and interface names, you can also type-hint for arrays. The ‘null’ value is always allowed as a default:
function myFunction(MyClass $object = null) {
//if no argument is passed, or if a null is passed explicitly, this function will work
}
But you cannot have something like this:
function myFunction(MyClass $object = new MyClass()) {
//this code will not parse
}
Oddly enough though, you CAN do this:
function myFunction(array $array = array()) {
//this code is perfectly legit
}
And you cannot type-hint for scalars, like ‘int’, ‘float’, or ‘string’:
function myFunction(int $int) {
//won’t work in PHP 5 – maybe PHP 6 will allow?
}
However, there is one warning to bear in mind with this approach. If the argument is NOT an instance of MyClass (or a child, or an implementer) your script will trigger a catchable fatal error, not an exception. In order to deal with this type of fatal error, you need to create a global-scope function and use it as the argument in a call to ‘set_error_handler()’ to replace PHP’s default handler. We’ll take a closer look at creating custom error handlers in another video, but here’s some code we could use in this situation:
{@todo – write and test example error-handler code}
However, if you’d rather not deal with custom error handlers, there are other ways to ensure that your function is getting the variable type you expect, and still make it clear to those who follow what is expected. There is a special docblock comment tagline “@param”. If you use a development environment such as Zend Studio, or run phpDocumentor on your code, the argument requirement will be listed along with the function documentation. And if you want to halt execution when the wrong argument type is passed, you can test the type explicitly within your function and throw an exception that can be caught and handled properly. Here’s what that looks like in practice:
/**
* this function does something useful
* @param MyClass $object
*/
function myFunction($object) {
if(! $object instanceof MyClass) {
throw new InvalidArgumentException(‘$object must be an instance of MyClass’);
}
//do something
}
We’ll look more at docblock comments as well as phpDocumentor in another video. But suffice to say this approach will work in many of the situations when you might consider using type-hinting, and it can be made to work with multiple types and scalars. The disadvantage, of course, is somewhat longer code, and needing to ensure that your function is called within the scope of a matching try-catch block.
The “instanceof” keyword, by the way, is also new to PHP 5. It’s essentially an analog to the is_a() function that’s been around since PHP 4. Like type-hinting, it tests whether an object is an instance of, a child of, or an implementation of the class or interface name in the right-hand argument.
For a while, the PHP engineers had decided to deprecate “is_a()” in favor of the instanceof keyword, and in PHP 5 before 5.3, it would toss an E_STRICT warning. However, as of PHP 5.3 it is no longer deprecated. Both is_a() and instanceof are now considered equally valid.
Perhaps the most significant change between PHP 4 and 5 is the fact that objects are now passed by reference by default. The reason I say it’s the most significant isn’t because it completely revolutionizes the language – PHP 4 could pass objects by reference by using the ‘&’ in front of variables in a function definition, as in the example shown here:
function myFunction(&$obj) {
//In PHP 4, $obj is a reference to an object, rather than a copy of it
}
The reason it’s so significant is because, while the PHP engineers worked very hard to make sure almost all PHP 4 scripts would work the same under PHP 5, this is one area where they might not. Consider the following code:
class Account {
var $balance = 0;
static function addFunds($account, $amount) {
$account->balance += $amount;
}
}
$account = new Account();
Account::addFunds($account, 20);
echo $account->balance;
In PHP 5, the output will be ’20’, but in PHP 4, no change actually takes place to the $account object, so the output is ‘0’. Under PHP 4, the function gets a copy of the $account variable, rather than a reference to the original variable as it does in PHP 5. And in this example, obviously it’s the PHP 5 behavior that would be intended. But that’s not always the case.
Imagine that a PHP 4 script were written that takes an object and performs some action on it with the expectation that it NOT change the original object. Trying to run that same script in PHP 5 could result in very unexpected behavior. And indeed, if your old scripts break when running under PHP 5, there’s a good chance that this new behavior is behind it.
Now, because there are some situations where you want the ability to work on a copy of an object rather than the object itself, PHP 5 provides an easy mechanism for doing that.
$object = new MyClass(5, 5);
$copyOfObject = clone $object;
In this case, any properties set in $object will be set identically in $copyOfObject, so making changes to $copyOfObject won’t affect $object. In another video we look at how you can have more fine-grained control over exactly how an object is copied by defining the __clone() method in your class, but for most cases, the default behavior of ‘clone’ is sufficient.
The final addition to PHP 5 we’re going to look at is called “indirect referencing”. And it’s a great way to take many lines of code and turn them into just a few. Consider this example from a typical PHP 4 script:
$var1 = $object->var1;
$var2 = $var1->var2;
var1 is actually an object itself that also happens to be a property on $object, and var2 is a property of var1. In PHP 5 we can shorten this to just:
$var2 = $object->var1->var2;
In PHP 5, there is no need to actually declare temporary variables in these types of situations. The code above will simply get the first variable and then use it to get the subsequent variable. It works for functions and methods as well:
$var2 = $object->method1()->var2;
$var2 = myFunction()->var2;
$var8 = $object->var1->method2()->var3->method4()->method5()->var6->var7->var8;
//so long as an object is returned with each ‘get’ or method call (aside from the last), all these examples are valid!
Indirect referencing leads to a handy programming technique called “chaining”. The last example shows how it can drastically shorten code versus PHP 4.
There were a number of other important changes introduced in PHP 5, and several of those will be examined in the section on Object Oriented Programming, but this concludes the ones I wanted to look at here.
October 14 2009 | introduction and PHP tutorial scripts | Comments Off on What was introduced in PHP 5
PHP 5 introduced something that programmers in other languages had come to rely on for exception handling. It’s called the try-catch block. In most languages that use the try-catch block, any time a run-time error occurs, it can be trapped inside a catch statement and dealt with in some manner appropriate for that particular situation. This is not the case in PHP 5.
Actual errors that the PHP engine generates aren’t considered exceptions the way they’re defined here, which is why it’s important to understand the difference between errors and exceptions. But if you want your code to generate and deal with procedural anomalies of any sort, or if you just want to halt execution without using a return statement, then exceptions are a fantastic tool to learn. PHP does provide a means for actual error-handling, but that topic is covered in another video.
So anyway, with the try-catch blocks, here is the basic syntax:
try {
//run some code
} catch(Exception $e) {
//do something
}
Basically, the code inside the try block runs, and if it causes an exception to be thrown, then execution of that block stops immediately, and the engine jumps into the catch block to begin execution. Exceptions are only thrown by actual PHP code. So your scripts and libraries may throw an exception, but if there’s an error within the PHP engine itself, the catch block won’t be triggered.
Take a look at the following example:
if($db->connect() === false) {
throw new Exception(‘could not connect to database’);
}
If this particular code is executed from within a try block, and the connect() method returns false, then the corresponding catch block will be called. It’s important to note that uncaught exceptions result in fatal errors, so don’t throw them unless you’re sure there’s a catch clause to deal with it. Alternately, if you want a last-resort catch clause, you can set a global exception handler. However, since the syntax for that is so similar to setting a custom error handler, I talk about that in the same video where I discuss setting custom error handlers.
The throw statement can act similar to a return in that it halts execution of a function (or at least, it will if it isn’t thrown within a try block), but instead of just returning to the point where that function was actually called, it continues up the stack until it finds a corresponding catch block.
Now, what I mean by corresponding catch block is one that matches the type of exception being thrown. The example above uses the basic class “Exception”, but that’s not the only option. PHP 5 provides several more specific Exception classes you can use, and it’s a simple matter to create your own. The catch block makes it clear what type of exception it can receive. Since all exceptions are based on the “Exception” class, a catch block like this:
catch(Exception $e)
will catch any type of exception thrown in its corresponding try block.
But supposing I wanted to handle different types of exceptions differently. A single try block can lead to multiple catch blocks:
try {
throw new UnexpectedValueException(‘unexpected!’);
} catch(InvalidArgumentException $i) {
echo ‘InvalidArgumentException: ‘ . $i->getMessage();
} catch(UnexpectedValueException $u) {
echo ‘UnexpectedValueException: ‘ . $u->getMessage();
} catch(Exception $e) {
echo ‘Exception: ‘ . $e->getMessage();
}
The code shown here will display “UnexpectedValueException: unexpected!” because the second catch block is the one that corresponds to the type of error thrown. However, since all exceptions are of the type “Exception” changing the code to the form shown below will change the output:
try {
throw new UnexpectedValueException(‘unexpected!’);
} catch(InvalidArgumentException $i) {
echo ‘InvalidArgumentException: ‘ . $i->getMessage();
} catch(Exception $e) {
echo ‘Exception: ‘ . $e->getMessage();
} catch(UnexpectedValueException $u) {
echo ‘UnexpectedValueException: ‘ . $u->getMessage();
}
This code will display “Exception: unexpected!”. That’s because PHP will go through each catch block in order until it finds one that matches, and then it will stop. Even though “catch(UnexpectedValueException $u)” is the BEST match, “catch(Exception $e)” is the FIRST match.
Alternately, the example below will simply cause a fatal error unless it’s called within the scope of a matching try-catch block higher up in the stack:
try {
throw new UnexpectedValueException(‘unexpected!’);
} catch(InvalidArgumentException $i) {
echo ‘InvalidArgumentException: ‘ . $i->getMessage();
}
Since the type of exception thrown doesn’t match any catch block.
In the above examples I used, InvalidArgumentException and UnexpectedValueException are actually built into PHP 5, along with several others. But inventing your own exception class is as simple as:
class MyNewException extends Exception { //no class code needed!
}
Include that class definition somewhere in your project space, and you can throw and catch MyNewException wherever you want. The name just helps differentiate exception types. This technique is useful for detecting when something unexpected has happened and dealing with it.
When catching an exception, the argument after the type of exception is a reference to the actual exception itself. In the case of:
try {
//do something
catch(Exception $e) {
//do something
}
“$e” is the specific object of the Exception class that was thrown and caught.
The exception class itself provides several methods you should know about. You can see more examples by searching php.net.
$e->getMessage();
Exceptions can be thrown with no arguments, but for debugging purposes, it’s usually helpful to include at least the first argument, a string, telling why the exception was thrown. For instance, if the script does this:
try {
throw new Exception(‘Go directly to the catch block’);
} catch(Exception $e) {
echo $e->getMessage();
}
the script will print “Go directly to the catch block”. Obviously, this isn’t a particularly helpful message, but you get the idea.
The second argument for an exception, if provided, is a code. Again, you can choose whatever you want, and calling “getCode()” will just return whatever you provided. Some programmers prefer to use numbers to classify their exceptions, since they can be a little less ambiguous than strings. And obviously, there’s no reason you can’t use both messages and codes in your exception. Here’s the syntax:
$e->getCode();
And an example:
define(‘EXAMPLE_EXCEPTION’, 55);
try {
throw new Exception(‘an example exception occurred’, EXAMPLE_EXCEPTION);
} catch(Exception $e) {
echo $e->getCode();
}
And this script would print “55”.
The final argument for creating an exception is another exception. The idea is that if an exception is caught in one catch block, and then a new one is thrown again, the newer exception can contain a reference to the old one. This isn’t something you see very often, but it’s easy enough to understand. Here’s another simple example:
try {
try {
throw new Exception(‘This is the way it is’);
} catch(Exception $e1) {
throw new Exception(‘Here is what I think’, null, $e1);
}
} catch(Exception $e2) {
$e1 = $e2->getPrevious();
echo $e2->getMessage() . ”
“;
echo $e1->getMessage();
}
And this code will print “Here is what I think” followed by “This is the way it is” on the line below.
In addition, the exception can return information about the stack at the time it was thrown. There are a couple different functions for this depending on whether you want the back trace as a string or an array, or whether you just need the specific line or file where the exception took place. Here they are very briefly:
$e->getTraceAsString();
returns the entire trace as a string
$e->getTrace();
returns an array where each line in the stack is a separate element
$e->getFile();
returns the path to the file where the exception was thrown
$e->getLine();
returns the line number where the exception was thrown
October 13 2009 | introduction and PHP tutorial scripts | Comments Off on Exception-handling with try-catch blocks
PHP has become one of the most prominent web development languages in production today. Part of this is because it is so easy for someone to dabble with it and achieve immediate results. It takes very little expertise to incorporate PHP into an otherwise straightforward html page, and that makes it popular with many designers.
The fact that those first few steps are so easy helped the language achieve some of its initial adoption, but that’s only part of the reason it’s become so widespread. While a web designer might appreciate a simple way to rotate a banner ad, or change some style based on the date or time, a skilled web developer can actually power the entire website, from serving up content, to managing access permissions, and interacting with data from around the internet. PHP is a powerful language, and while that power can be dangerous, it can be incredibly freeing to a developer.
Most large websites, including heavyweights such as Google, Yahoo, Amazon, and Paypal, provide developers tools for interacting with them through their own PHP scripts.
Many websites – large and small – use PHP to power their content management system, or CMS.
And there are a number of open source projects, written in PHP, that harness the collective skill of thousands to create truly great software. My personal website, powered by WordPress, is one example of such an effort. Others you might be familiar with include Joomla, Drupal, and phpBB.
The goal of this training course will be to take you from a basic understanding of PHP to what can be called an advanced level. At this point, you should already be comfortable writing functions and classes, using the basic language constructs like loops and conditional statements, connecting your scripts with a database and interacting with the server’s filesystem. You should know some of the more common functions provided by PHP itself, and for the most part, you should be able to look at another developer’s PHP code and figure out what it does.
At an advanced level however, you’ll need to be aware of the various tools and libraries available to you as a developer and how to incorporate them. You’ll want to gain a deep understanding of how object-oriented programming should work in PHP, so you can put it to the best possible use in your scripts. And perhaps most important, you’ll need to learn how to secure your websites and web applications against all the ways someone might try to exploit them.
PHP has earned its place of prominence because of its ease of use, power, and scalability. It is well supported, and well documented, and is unlikely to lose its popularity within the foreseeable future.
October 13 2009 | introduction and PHP tutorial scripts | Comments Off on Introduction