« Looking For A PHP Development Job | To The New PHP Programmers… » |
PHP allows developers to write a variety of different styles of code: procedural, object-oriented, or simply scripts. This flexibility makes PHP easy to learn, and also means that new developers to PHP may not be programmers in other languages.
For new developers, especially developers who have never been programmers before, moving from writing simple scripts to writing functions is a process that takes time. I developed in PHP for years before I wrote a single function. I also never found a comprehensive tutorial on how functions work, or how to write them. There’s documentation in the manual, but it’s a bit hard to grasp if you’re new. This article is about writing functions.
For starters, what is a function? A function is a collection of code that is available for use and reuse repeatedly throughout a particular script or application. You’re probably already familiar with functions because you probably use them in PHP. If you’ve used print() or mysql_connect() you’ve used a function. Both of these functions encapsulate other code (in their case, core PHP code written in C), and allow you to accomplish certain tasks.
Matthew Turland equates writing a function to tasking a junior level employee. After describing a short name for a particular task, you teach the scope of that task, and then can direct the task to be executed at any time.
The beauty of functions is that you don’t have to rewrite the same code over and over again. Once it’s encapsulated in a function, that function provides a shortcut to executing the code you’ve defined. This is a pretty cool tool when you think about it.
For example, let’s say that you establish a MySQL connection every single page. You could do the following on every page:
$connection = mysql_connect('localhost', 'user', 'pass'); mysql_select_db('mydatabase');
Or, you can write a function that does this, and call the following on every page:
$connection = myConnectionFunc();
Which would be easier for you? Well, the second one of course. Let’s learn how we did that.
The source code behind myConnectionFunc() is pretty basic. If you don’t understand the syntax entirely from looking at it, don’t worry. I will explain.
<?php function myConnectionFunc($host = 'localhost', $user = 'user', $pass = 'pass', $database = 'mydatabase') { $conn = mysql_connect($host, $user, $pass); mysql_select_db($database); return $conn; } [/sourcecode] That may look quite complicated but once you understand the syntax, it's not all that complicated at all. We'll come back to this example once we know a little bit more about functions. <strong>All Functions Share These Characteristics</strong> For starters, all functions share certain characteristics. The function definition starts with the word "function", followed by the name of the function, an opening parenthesis, any arguments, and a closing parenthesis. You must also include curly braces to delimit the body of the function. Here is the most basic function you can have in PHP: function basic() { }
All functions should share these qualities. They are required by the PHP engine to determine that a function has been defined. Without them, you will get a syntax error.
Function Bodies
A function body can contain any user-defined (that’s functions you write) or internal (that’s functions PHP provides by default) functions, structures, and code that you like. Remember: functions serve to encapsulate the functionality you want to express, meaning that a function can be called repeatedly to accomplish a certain task. For example, a function can look like this:
function iterateArray($array) { foreach($array as $item) { $newArray[] = 'Iterated: ' . $item; } return $newArray; }
What you put in the body is largely up to you. There are few (if any) restrictions. Bear in mind, that there are best practices; you should make yourself aware of them through the PHP manual and further reading.
Function Scope, Arguments, and Return Values
One of the most important things (and most difficult concepts to grasp) about functions is the concept of a function’s scope.
Functions don’t know about what is going on outside the function. They don’t know what variables have been defined, or what is going on around your application at the time you invoke them. They only know about the information they have been given, and the contents of their bodies. This behavior is necessary because if functions were aware of the “global scope” (all the variables and information that is defined in your application), you could get very unpredictable behavior. Instead, they are “dumb code units”, as Matthew Turland describes it.
Similarly, when a function ends, anything that happened inside of it is forgotten. This is to prevent the function from improperly altering behavior in your application, which would also result in some very strange bugs.
But this creates a big problem: how on earth do we get information into and out of a function?
To get information in, we pass the function some arguments. An argument is a variable that exists between the parenthesis in the declaration. See the example below, with the variable $argument:
placeholder for ANY value we want to give it. That variable need not be named $argument. The function doesn’t care if the global scope has a variable named $argument; it only cares about what you give its placeholder.
You can have multiple arguments. You only need to separate them by a comma. Convention says that you should add a space after each comma, but that’s entirely up to you and your own personal coding standard; it is not required by the parser.
How do we get information out of a function? In the previous example, we used the echo() construct to directly output our statement, but this wouldn’t work if we had assembled an array, for example. Since everything inside a function is destroyed when the function’s execution ends, we’ve got to use a different method to get information out of a function: the language construct ‘return‘.
This language construct allows us to return a value from the function. It also has the benefit of halting execution of the function, meaning we can use it to return a value early if we’re done executing the function. You can return any PHP type, including the value of a variable. Note that returning a variable does not place that variable into the global scope; it returns the value only. For example:
Default Argument Values
You may have noticed in our initial example that I added an equals sign and a string value after defining the arguments. This is a perfectly valid technique, which adds a default value to each of the arguments. You may assign a default value to some, all, or none of your arguments, as you see fit.
The benefit of default argument values is that it allows you to call the function without having to set default values each time. For example, in our initial function the login credentials are unlikely to change. However, by permitting arguments, you are allowed to connect to a different database or database server. If you assign values to the arguments when you call the function, they automatically override the default values in the definition.
Bear in mind that if you want to assign some of your arguments default values, it is best to place these arguments towards the end of your function signature. The reason is that if you place them at the front, you will have to assign them a null value. For example:
Returning Multiple Values From A Function
PHP does not allow for the return of two values from a function. This is a limitation of the language’s structure. However, it is possible to return an array from a function, which results in similar functionality. For example:
objects, if you like. This is considered an acceptable practice.
Bringing The Global Scope Into Your Function
It is possible to bring parts of the global scope into your application by using the keyword ‘global’. The global keyword allows you to define variables that exist in the global scope as variables that also exist in the function’s internal scope.
For example:
are reflected in the global scope.
This is a very bad programming practice. Typically, if you are finding it necessary to pass variables into a function through the global scope, you should consider how your code can be refactored so that this is no longer necessary.
Passing By Reference
When you define arguments for a normal function, these arguments are given to the function in a fashion that is known as “by value.” Essentially, PHP copies the value of the variable, and then gives it to the function. Changes to that copy are not reflected in the global scope.
There is another way to pass to and return from functions: by reference. Passing “by reference” means that rather than copying the value, you are tying the two variables together. When you alter the value of one variable, you alter the value of the second. For example:
<?php $var1 = 'a'; $var2 =& $var1; $var2 = 'b'; echo $var1; //outputs 'b'
In this example, we attach the two by reference, making our change to $var2 reflected in $var1. You can also do this with functions:
<?php function addOne(&$num) { $num++; } $var = 6; addOne($var); echo $var; // Outputs 7
Note that even though we did not return anything from addOne(), the $var value was affected in the global scope. This is because we passed it by reference when we defined the function. This tied the value of $var to $num, and when we incremented $num, we also incremented $var.
Passing by reference should always be done when you define the function. You should never pass by reference at runtime. For example, the following syntax would be unacceptable:
function addOne($num) { $num++; } $var = 6; addOne(&$var);
While this behavior will not break in PHP 5, it will probably not be allowed in PHP 6, and will emit a nasty warning if you do it.
Bear in mind that when passing by reference, a variable is the only thing you may pass. You cannot pass an expression or any other value to a function that expects a variable passed by reference.
With regards to references as a programming practice, be aware that references aren’t doing what you think they are behind the scenes. While they have very limited application, you should understand the implications, and more often than not, you will want to pass by value.
Conclusion
By now, you’ve had a chance to be exposed to some of PHP’s most common function behavior and, hopefully, will be able to write functions yourself. Functions provide a powerful way to encapsulate and extend your code, share common functionality without writing it for each occasion, and improving your ability to prevent bugs.
This blog entry implements The Beginner Pattern.
Brandon Savage is the author of Mastering Object Oriented PHP and Practical Design Patterns in PHP
Posted on 10/12/2009 at 1:00 am
Niels wrote at 10/12/2009 1:53 am:
Scripting is not a programming paradigm[1] like object-orientation or procedural ;-) It expresses just the fact that programs of a scripting language need not be compiled before execution.
Flyingmana wrote at 10/12/2009 3:21 am:
I think its important to say, that objects since PHP 5 always are passed by reference.
Ulf Wendel wrote at 10/12/2009 4:20 am:
… and if you are beginner and use ext/mysql you code crap. The current MySQL extension is ext/mysqli. The php.net manual tells you why.
Sky wrote at 10/12/2009 10:48 am:
Hello
Why do you use this :
function goodFunc($var2, $var1 == false)When you can use this :
function goodFunc($var2, $var1 = false)The default value of a variable is a definition, not a comparaison.
Sry if i got something whrong.
Brandon Savage (@brandonsavage) wrote at 10/12/2009 10:58 am:
Sky, you caught a mistake I made and didn’t catch when I was proofreading. Good eye!
I’ve fixed the mistake.
Bruce Weirdan wrote at 10/12/2009 5:32 pm:
> Bear in mind that if you want to assign some of your arguments
> default values, it is best to place these arguments towards the
> end of your function signature. The reason is that if you place
> them at the front, you will have to assign them a null value.
Unlike you imply this will not have the same effect as not passing the argument, as illustrated by the following example:[weirdan@home ~]$ php -r ‘echo PHP_VERSION . PHP_EOL; function a($b = false, $c = false) { var_dump($b, $c); } a(null);’
5.2.8
NULL
bool(false)
[weirdan@home ~]$As you can see, $b is null inside the function, just what was passed to the function.
Your goodFunc example have a syntax error:
function goodFunc($var2, $var1 == false) // <— it should be $var1 = false
Bruce Weirdan wrote at 10/12/2009 5:36 pm:
> I think its important to say, that objects since PHP 5 always are passed by reference.
Well, it’s not true. In fact Brandon linked in this very blog post to the article by Sara Golemon that specifically deals with this very misconception.
Brandon Savage (@brandonsavage) wrote at 10/12/2009 5:39 pm:
Hey Bruce, I fixed that syntax error earlier, and it looks to be fixed in my version. Are you seeing it differently?
Bruce Weirdan wrote at 10/12/2009 5:55 pm:
> Hey Bruce, I fixed that syntax error earlier, and it looks to be fixed in my version. Are you seeing it differently?
No, I just had this tab opened since morning, and forgot to refresh prior to posting.
Samuel Folkes (@SamuelFolkes) wrote at 10/26/2009 12:13 am:
Excellent article. I just have one teensy tiny problem: print() is actually not a function. Its a language construct. That aside, good work!
Brandon Savage (@brandonsavage) wrote at 10/26/2009 5:48 am:
I always make the mistake of confusing print() with a function because it has a return value, unlike echo(). My bad!
« Looking For A PHP Development Job | To The New PHP Programmers… » |