Forum Moderators: coopster
Could somebody take pity on a poor distraught soul and share a few parameter-including, custom functions with some comments on how and why they work, and an example or two of how they work in context? I learn best through examples with explanations, and my books aren't quite cutting the mustard in this respect.
Any and all help will be greatly appreciated.
Thanks,
Matthew
function definition: the function script that you write
function call: an instance of the function being used
A function without arguments
function myfunc()
{
return "this doesn't do anything";
}...
echo myfunc(); // returns "this doesn't do anything"
So far so good.
Now, if I add arguments, they must be of the same type and number in the function call as in the function definition.
function myfunc($myarray, $myvar)
{
$return_val = "";
if ($myvar)
{
foreach($myvar as $val)
{
$return_val .= $val;
}
}
return $return_val;
}$myvar = true;
$myarray = array("three plus ", "one ", "equals four");echo myfunc($myarray, $myvar); // returns "three plus one equals four"
If $myarray were set to a simple string rather than an array, it would crash. If one of the two arguments were missing, it would also crash. so sometimes we want to make the arguments optional.
function myfunc($myarray, $myvar=false)
{
$return_val = "";
if ($myvar)
{
foreach($myvar as $val)
{
$return_val .= $val;
}
return $return_val;
}
else
{
return "I don't work for free";
}
}
.....$myarray = array("three plus ", "one ", "equals four");
echo myfunc($myarray); // returns "I don't work for free"
Now $myvar is undefined, but it doesn't crash because it has a default value.
Next lesson: SCOPE and returning values...
[edited by: ergophobe at 3:27 pm (utc) on Jan. 8, 2005]
Even with your concise explanation above, though, I find I'm still having difficulty creating functions that "do" things. For instance, in a script I'm working on now, I'll frequently need to remove underscores from variables and replace them with spaces. I've tried several things, including this:
<?php$string = "string_string";
echo "<p>$string</p>";
function remove_underscores($string)
{
global $string;
eregi_replace('_', ' ', $string);
}echo remove_underscores($string);
$string = remove_underscores($string);
echo "<p>$string</p>";
?>
I would have expected this to replace underscores with spaces in any variable named $string. But, it doesn't. Even more useful would be a function that would replace underscores with spaces in any variable, regardless of what it's named. How might I go about doing this?
Someday I'll be the one to answer basic questions like this one, eh? ;)
function spaceformat($str) {
$str=str_replace("_", " ", $str);
return($str);
}
echo (spaceformat($str));
?>
In most programing langauges, things have values, for instance the integer 5 has the value of 5, the string "hello" has the value of "hello", the variable $test has whatever value you tell it to have, these 'values' are what the compiler, or parser "returns"
For instance the function:
float sqrt ( float arg)
Takes a float, and returns the square root of it. When you write your own functions you have to let the compiler know what to return, that is if you want to return anything. This is achieved with the return(); function I used above.
Check out [us3.php.net...]
You might want to stay away from globals for now, classes are better for that in my opinion, but before you learn classes you should learn functions.
The reason your script was not working was that your custom function "remove_underscores" was not returning a value.
To have a function return a value you need to have a "return" statement which returns a string or variable.
Also the "global $string" statement is not needed because the function already has access to $string because it is passed as a parameter.
The code below should do what you were trying to do:
<?php$string = "string_string";
echo "<p>$string</p>";
function remove_underscores($string)
{
// global $string;
[b]return[/b] eregi_replace('_', ' ', $string);
}
echo remove_underscores($string);
$string = remove_underscores($string);
echo "<p>$string</p>";
?>
Hope this helps,
Elijah
Rather than links throughout, I have a list of relevant links to the PHP Manual at the end.
Variables in PHP are either local or global in scope. Knowing the "scope" of a variable essentially tells us from where we can access a variable.
- variables declared in the main script and not encapsulated in a function of class, are global and are avaiable everywhere in the main script.
- variables declared in functions or classes are local to that function or class, and are only available within the function where they are declared.
This last point is fundamental - the most important concept with respect to functions and scope is to understand that variables within functions are local unless otherwise declared. What does this mean? Essentially, it means that the problem you came up against is entirely predictable if you understand variable scope.
function myfunc($a)
{
$a++;
}$a = 10;
myfunc($a);
echo $a;
Q: What's the output?
A: 10
Why? Because the $a within the function and the $a outside the function are different variables. They have nothing to do with each other. As far as the PHP processor is concerned, the fact that the have the same name is entirely coincidental. To put it figuratively, the fact that I tell a secret to one guy named Matthew out in the lobby does not mean that every guy named Matthew in each and every office now knows that secret.
So what do you do? As the previous posters mentioned, you must both pass and return a value. Note, in the previously example I did not pass a variable to the function, I passed a value that was then assigned to the local variable, coincidentally named "$a" within the function. However, no value was returned, so the function does nothing. Once I leave the function, the local variables are thrown away never to be seen again. That is fundamental to understanding functions and scope.
It's also a great thing for creating trouble-free scripts. What this means is that if you and I are working together, I can write a main script that needs a few functions. I tell you what arguments the functions takes and what values it needs to return. You can then use any variable names you want within the function without having to see, know or understand my script. There will be no conflict.
If I want the variable outside the function to be modified, I must assign a new value to it based on the return value of the function.
function myfunc($b)
{
$b++;
return $b;
}$a = 10;
$a = myfunc($a);echo $a;
Q: What's the output?
A: 11
This is because we passed the value of $a into the function, and the passed the value of the local variable $b back out to the main script and then assigned it to the original variable $a.
This mechanism gives us excellent control of how our functions interact with the rest of the program and allows us to avoid unintended consequences.
Now, what if you actually do want the function to interact with values from the main script without having to pass every one as an argument? I try to use one of two mechanisms:
1. if the value will be constant, define a constant in the main script. Because a constant can't be changed, there are fewer worries about unintended consequences and therefore constants declared in the main script are available to all functions. I use constants a lot for configuration values. If possible, I always use constants rather than variables.
2. Use the so-called super global arrays where appropriate. These are the $_GET, $_POST, $_COOKIE, $_SESSION arrays. If you had been at this a bit longer, you would remember when PHP required you to pass $HTTP_*_VARS to every function. If you play around with a lot of scripts that have been around for a while, you'll still see these $HTTP_*_VARS. These arrays have been deprecated and that saves us passing get and post vars all around.
If neither of those do it for you, there are still two more methods that allow you to act directly on a variable from within a function
- pass by reference
- global declaration.
Remember how I said that normally you are passing the value of a variable to the function? Well, it is also possible to pass a reference to the variable. Essentially, you can think of it like a phone number A that rings through to a given phone, which also rings when someone dials B. Two separate numbers, one phone. In PHP, B does not point to A and vice-versa when one "references" the other. Rather, they both point to the same place. Whether you call A or B, you interact with the same person. whether you call it $a or $b, they both point to the same data (not the same value, but the same actual data). In PHP, we accomplish this by adding an "&" in front of a function argument in the function definition, not in the function call.
function myfunc(&$b)
{
$b++;
}$a = 10;
myfunc($a);echo $a;
Q: What's the output?
A: 11
Why, because $b is the "ring through" number and even though we've called it something else, it's acting on $a.
function myfunc(&$b)
{
$b++;
}$a = 10;
myfunc($a);echo $a;
Q: What's the output?
A: 11
Remember I said that variables in functions are local unless otherwise declared? There is another mechanism that allows a function to interact with a variable. Within a function we can also declare a variable to be global, meaning that though it appears in the function, it's really the same variable as the variable of the same name that exists in the global scope. In other words, the fact that the variable has the same name within the function and outside it is no longer a coincidence, as far as the PHP processor is concerned. Rather it is the same variable. This time when I tell a secret to Matthew, it's always just one guy.
I use pass by reference primarily for passing large arrays or class objects to functions, largely to save the overhead of creating a copy (this is no longer necessary with classes in PHP 5).
function myfunc()
{
global $a;
$a++;
}$a = 10;
myfunc($a);echo $a;
Q: What's the output?
A: 11
Why, because this time we are in fact modifying the same $a inside the function as the one we're echoing outside the function. Notice that I do not pass the variable as a parameter if I am also declaring it as global as Elijah already advised.
Honestly, I almost never use "global" if I can avoid it; I never use it just to save on typing. It's just one of those things - when I took my first FORTRAN and Pascal courses years ago, the profs always said to avoid "global" and "goto" or your programs would get hard to follow, and it still seems like good advice to me, but that's just my opinion.
Finally, I said that the value of a local variable within a funciton was thrown away when the function was done. What if, however, you want the value to persist? In that case, you declare a static variable;
function myfunc()
{
static $a=1;
return $a++;
}echo myfunc() . ", " . myfunc() . ", " . $myfunc();
ouptut: 1, 2, 3
Because we've told the PHP processor not to throw the value away, it persists between function calls and the persistent value overrides the default value assigned the first time the function is called.
FROM THE MANUAL
Variable Scope [php.net] - includes information on the use of "global", "static" and references.
Superglobals [us3.php.net]
Passing by reference [us3.php.net]
There's one more nice thing about functions. Function can call another function, or be recursive: call herself.
To count 7! you can use function:
<?PHPif(!function_exists('f'))
{
function f($number)
{
$number = (int)$number; //conversion to int
if($number) return $number * f($number - 1);
else return 1;
}
}echo "A ".f(0)."<br>"; //A: 1
echo "A ".f(1)."<br>"; //A: 1
echo "A ".f(3)."<br>"; //A: 6
echo "A ".f(bla)."<br>"; //A: 1
echo "A ".f(5bla)."<br>"; //A: 120
?>
I always use function function_exists, because you can't declare one function twice in PHP.
Also here is important to place (int)$number for the function to be foolproof.
However ergophope? How to do this:
function f((int)$number)
{}
?
It's not working with me.
Best regards. Hope it was a nice example with recurency. But beware! Endless loop will cause your php to stop working - you'll never get result. I did that once and had to restart php on the server :)
Michal Cibor
If you just want to make sure the argument is an integer, you have to cast it as such within the function. Usually this is done automatically. Your recursive function, for example, would work fine in PHP without the explicit casting as an integer. As soon as you do an operation like
$number -1
you have effectively cast $number as an integer.
As for recursion, you have to watch out not just for endless loops, but for eating up huge amounts of memory. I was pretty good at solving all sorts of things through recursion after doing some Scheme programming (which has no looping constructs other than recusrion - so no for or while loops). I don't find I use it much in PHP.
I'm sure I'll have more questions later, but I'll wait until I understand the issues discussed so far. Thanks again for helping out so much! ;)
For example, in C you had to define a variable as global and you always had to type cast variables. Nice thing about php is they cut all the redundecy out by eliminating the need to do these things, which is why I could see if you have never used a programming language like C, or possibly Java, it could become very confusing.
You might think about backtracking and picking up a beginner C or C++ book and going through the motions. It will just make more sense because it forces you to define and declare everything. You may be able to get through functions but you might run into much more confusion when you start trying to build classes in php.
So yes, I guess I'll have to forgive you for slamming my favorite browser! ;) Actually I know very well you weren't really slamming it; I always love a good FireFox discussion anyway. ;)
On another note, I am having a little difficulty with one of my custom functions. I don't understand its behavior at all. More details here [webmasterworld.com].
Again, many thanks for your help!
Matthew