13th December, 2005
Functions 101
Tuesday, 1:53 am in CodeGirl
So, the other night I was playing around with the idea of using Enth3 to run my neglected fanlisting site. At the moment they use a hacked up version of the ultra-common and ultra-trashy phpFanBase because I couldn’t bring myself to use that script ‘raw’ and couldn’t be arsed writing something from scratch. Since I’m a code-snob and all, I was always going to ‘get around to it’ eventually but until that magical day I think I will use Enth3 instead.
Enth3 is a weird script; it seems to be far too much bloatware for its own good. It’s also got this overtly obtuse setup and its installation proceedure is mostly hidden under big paragraphs from the author telling us the EULA in no uncertain terms. It uses case()‘es a lot, and I mean a lot. It even uses the case() ‘fallthrough’ phenomenon as a kind of ‘or’ statement. However, most importantly, it uses functions… but again, weirdly. Each function re-includes the config.php. The only reasons I can think why someone would do this would be as either a kind of substitute global directive for inheritence in functions, or as some kind of register_globals on security measure… thing. Maybe it’s just my formal C training coming through; a header is a header is where you include things. Not in the middle of the file. But as far as what’s considered ‘good form’ in PHP… I’m not sure. Odd.
Anyway, I was talking about functions! Functions are awesome, I really, really approve of functions. Part of my code-snobbery is refusing to use code that doesn’t make use of functions. Even the tiny sk.include uses a function! phpFanBase didn’t use functions, ergo it got re-written. Whatever script it was ~starfyre [h] was trying to run her webrings with didn’t have functions, ergo it got scrapped and I wrote sk.ring instead.
Function Over Form
Everyone should use functions, they’re really easy. Look:
<?php
print_me();
function print_me(){
print "Hellow World!";
}
?>
That’s pretty much the simplest function I can think of. I suppose you’re now asking, “What the hell is the point?” To which I reply this:
<?php
$arr = array ( 'foo', 'bar, 'baz' );
print_pre( $arr );
function print_pre( $var ){
print "<pre>";
print_r( $var );
print "</pre>";
}
?>
print_pre() is actually a function I use in sk.log, primarily for debugging. print_r() is a really useful PHP function which you can use to see the contents of things like arrays and objects. I use it all the time when I’m coding if I ‘lose’ a varaible, or to check that things liek my form data are submitting correctly. However, by itself print_r() is not particularly browser-readable since it formats via whitespace, which browsers ignore. So to make things easier for myself I use print_pre(), which will take any variable and print it out in a way that preserves its whitespace ‘format’.
And this is the most common use of functions; snippets of useful code you think you might like to use in more than one place. To make your own function (to declare it), you need to use the keyword function, followed by the function’s name (letters a-zA-Z, numbers 0-9, - and _), and a variable list enclosed in parentheses. The variable list should contain any variables you want the stuff ‘inside’ your function to use.
Functions have something known as scope, which means that the only variables accessable to a function are those that are either passed to it via its variable list, or those declared inside it. For example:
<?php
$str = "I am outside the function!";
change_str( $str );
print $str;
function change_str( $str ){
$str = "I am inside the function!";
}
?>
Will print:
I am outside the function!
This is because, even though they share a common name ($str), the variable inside the function is considered to be in that function’s local scope, while the initial $str is in the global scope.
The Returner
The easiest and most common way to get a function to ‘work’ on a variable is by using the return statement. return does pretty much exactly what it sounds like; you stick it in at the end of a function and it returns one variable to whatever scope it was called in (you can call functions within functions, of course). Remember: return returns one variable (use an array or object if you want more than one piece of data), and the function stops executing when it gets to a return.
For example, here’s a simple calculator:
<?php
$i = 5;
$j = 10;
$result = add_num( $i, $j );
print $result;
function add_num( $n, $m ){
return $n + $m;
print "This will not be printed, since it is after the 'return' statement!";
}
?>
Which will print ‘15’ to the browser. See how we’ve done our addition on the same line as the return statement? This is perfectly acceptable. On the other hand, we could have done, say, $n += $m; and returned $n, or even $tmp = $n + $m; and returned $tmp. There’s always more than one way to skin a baby in PHP.
Down the Scope
Speaking of skinning babies, there’s another way to manipulate variables using functions. Remember before I was talking about global and local scope? ‘Local scope’ refers to variables that are not inside ‘global scope’; generally things declared inside functions. (Technically I’ve been told that control blocks – things like while, if() and for() – also have their own local scopes, but I actually think this might be wrong… I think.)
Luckily, PHP has a ‘scope inheritence’ command; global. Take the following code:
<?php
$num = 0;
print $num;
inc_global();
print $num;
inc_global();
print $num;
function inc_global(){
global $num;
$num++;
}
?>
Here global tells us to work on the version of $num that has been declared in global scope, as opposed to creating one in local scope. We then directly change the value of it. Generally you will want to work on variables by passing them rather than using the global statement. The most common place you see it is to import variables declared in config files.
Oblique Referencing
The third way of using scope is functions within PHP is something that I’ve rarely actually used in PHP – in fact, I’ve done it exactly once; in one of the functions that helps work out sk.log’s ‘cuts’ – but that you find all over the place in other languages, such as C++ (not, however, C, which does kind of the same thing but with much more pain using pointers, something you thankfully will never, ever have to worry about in PHP). It’s using what’s known as a referenced variable. Referenced variables are functionally a little bit like varaibles imported by the global keyword, only more specific. Kinda.
Usually, whenever you pass a varaible to a function, the function makes a copy of that variables and works on the copy, rather than the original. The copy is then ‘destroyed’ (from a memory point of view) at the end of the function’s execution. If you return a value, that value is again copied back out into the scope it was called from (eg. in $ret = somefunction(); the variable $ret is created to hold somefunction()’s return value). However, if you pass a varible by reference, the function will not make a copy, and instead work on the original. It makes sense eventually, trust me.
Referenced variables are denoted by the & symbol:
<?php
$str = "This will be passed by reference.";
print "$str <br />";
byref( $str );
print "$str <br />";
function byref( &$refstr ){
$refstr = "Changing the string by reference...";
}
?>
Which will print:
This will be passed by reference.
Changing the string by reference…
Now remove the & symbol and see what it prints. That’s passing by reference.
“Just one second,” I hear you say. “You renamed $str to $refstr within the function; how come they’re still the same?”
That’s just what passing by reference does. Think of it a little bit like creating a shortcut to a program in Windows. You can call that shortcut whatever you want, but it still ‘points to’ the original file and will run that file when it’s clicked on. It’s the same with a referenced variable; whatever it’s called, it still points to (is an alias of) the original variable’s value.
Like I said before, hardly anyone in PHP uses referenced variables, simply because of the way PHP handled variables in general. Most languages are a lot stricter about what you can ‘put into’ a variable. For example, if in C++ I say I want a variable called foo to hold an int (a number, basically), that’s all it will hold. If I try and put a string into foo, the compiler will freak out. (Especially since strings don’t really exist in C++ in the same way they do in PHP; instead the most common type of ‘string’ is actually an array of chars, or single letters. And yes, you have to declare the length or the array up front, and yes that gives you headaches if you then want to change the value of that ‘c-string’ to something shorter or longer. Welcome to the wonderful world of programming.) The reason kind of has to do with raw memory allocation; compiled programming languages (like C/++) tend to be much more ‘visceral’ with how they manage memory than interpreted languages (like PHP). Which is really good if you’re writing, say, an OS, but not so good if you’re trying to write a webpage. This is, incidentally, why anyone who does CGI using C should be shot.
But you don’t really need to know any of that.
And that’s pretty much everything I have to say about functions. Wasn’t that Fun and Educatoinal?
- « Previous
- Next »