Controlling Data In Miniblocks Via Variables
There are no pages beneath this page
Submitted by ChrisW
In the previous tutorial we learned how to do interesting things by "calling" (running) functions. This time we'll take a look at variables and state.
We saw that functions can give us values to work with, such as the value of an ocPortal configuration option. We also saw that we can nest function calls; that is, use the value given by a function call as an argument for another function call, such as:
strtoupper(get_base_url()); // Get the site's base URL and make it uppercase
We can nest as many such calls as we like, for example:
This will give the number of digits in the length of an ocPortal site's "base URL" option. Remember that the arguments of a function are worked out first, then the function is called with those values. This means that "get_base_url()" will be worked out first, which gives a text string (from now on we'll refer to text as just "strings"), and this is given straight to the "strlen" function which gives us the number of letters and other characters in a string. This number is then sent to the "strval" function, which converts the number into a string of the number (ie. a number like 12 will become the string "12"). We then send this straight to the "strlen" function which, again, counts how many characters are in the string. Since the string is just that of a positive whole number, this will be the number of digits.
Using functions in the way shown above can get very confusing. Luckily there is a way to cut down on this confusion, once again borrowing an idea from Maths; the variable.
Rather than using variables to represent unknown values like in Maths (eg. "Solve for x") instead we can use variables to 'store' values temporarily, so that we can refer to them later. This is very useful if the result you want to work out depends on performing lots of steps, like the heavily nested function calls above. In PHP, variables are written as a name with a dollar sign, "$", at the beginning, for example
We can 'store' a value in a variable by saying that the variable is equal to the value (we call this "assigning" the variable), like this:
$url = get_base_url();
Now we can use the short name "$url" instead of the longer function call "get_base_url()" (its also more efficient, since the value only has to be worked out once). Notice the semicolon at the end, which means that this is an instruction to carry out (a "statement"). Assignment statements can do one of two things:
It is important to understand what PHP does when it sees an assignment statement, which is this:
1) Work out the value of what is on the right hand side.
2) Store this in the variable on the left hand side.
This means that the left hand side must be a variable name and nothing else and the right hand side must work out to the value we want and nothing else. This is different to the symmetric equalities found in Maths, where we can swap what's on each side around and it makes no difference, and also it means we can't get PHP to work out things like "$x + 20 = 25;", since "$x + 20" isn't a variable name (we can usually avoid such situations by using very simple algebra to rearrange the equation such that only the variable name is on the left).
Another very important difference between PHP and Maths is that in Maths we make statements which are 'timeless', ie. they are statements of truth which don't depend on how we say them. For example we could say "x = y" and "y = 5"; this, of course, means that "x = 5". In PHP however, everything is worked out in a sequence. If we try writing this example in PHP:
$x = $y;
$y = 5;
PHP will start at the top of whichever file it is given (eg. when a PHP file is accessed by a browser) and carry out each instruction it is given until it either reaches the end of the file or one of the instructions is to exit. On the way, it can go through other instructions if told to; for example a function call like "get_base_url()" is actually an instruction to go the definition of "get_base_url" (which lives deep within ocPortal's guts), run through those instructions, then come back when it's finished. The consequence is that PHP, unlike a person doing some Maths, is not smart enough to go looking through the code until it finds the definition of things; all it does is remember what it's been told previously.
The currently defined variables (and functions) along with their values makes up what is called the program's state (or 'memory'). As we saw, assignment can change the program's state by defining a new variable or changing the value stored in a variable. This second possibility is the one that causes the most confusion, since it seems to defy the laws of Maths. Consider the following, which all makes perfect sense if you understand the way PHP uses state:
$my_age = 22;
// Simple enough, $my_age now stores 22
$my_age_string = strval($my_age);
// $my_age_string now stores the string "22"
$my_age = $my_age + 1;
// The above line makes no sense if we think in terms of regular
// Maths, but it does make sense in PHP.
// First the right hand side will be worked out to give the value
// 23, then this will be assigned to $my_age, so that $my_age now
// stores the value 23. This line has changed the program's state
$my_new_age_string = strval($my_age);
// $my_new_age_string stores the string "23", but $my_age_string
// still stores "22" since it was defined before the state
// changed. Thus we've used the same code, "strval($my_age)",
// and received different results, because it depends on the
// state of the program; specifically, the state of $my_age.
Since we can change the value of our variables at any time, we have to be careful about any assumptions we make about these values. For example, just because you see "$my_variable = 12;" in some part of the code, this doesn't mean that you can write some new code somewhere else that uses $my_variable and assume it is 12, since the state may have changed in-between, or your code might run before that definition is made (in fact PHP has a feature called scope which will stop you making such assumptions, which will be explained in a later tutorial).
Don't worry if you find the idea of state difficult to grasp at first; although it is very powerful, stateful programming can be fraught with bugs and is very hard to model and describe Mathematically (ie. it's very hard to prove whether state is being used correctly).
Personally, I favour defining new variables for things as I go (a loose form of the 'single assignment' programming style), rather than using a few variables and constantly changing the values they store. Although re-using variables makes more efficient use of memory (we overwrite any old values we don't need any more, rather than remembering them) it can cause easily avoidable headaches. For example, consider this piece of code:
// Get the site's base URL
$address = get_base_url();
// Send the user a HTML "anchor" which links to the site's base URL
echo '<a href="';
echo htmlentities($address); // htmlentities turns strings into a form that won't interfere with HTML
// Take some parameters from a submitted form
$name = post_param('name');
$age = post_param_integer('age');
$address = post_param('address');
// Send a message to the user
echo '<p>Hello ';
echo ' of ';
echo ', I see that you are ';
echo ' years old.';
// Give the user another homepage link
echo '<a href="';
echo '">Go back to the homepage</a>';
Here we've used the variable $address for storing both the Web site's address and the user's home address. This has caused a bug since the "Go back to the homepage" link won't work, as it's trying to link to the user's home address! This bug isn't completely obvious, and PHP certainly won't spot it. We can fix it by either repeating the line
$address = get_base_url();
A Miniblock Example
Now that we've learned about variables, let's see how we can use them to make a seemingly complicated miniblock much simpler. Here we find out how many site points the current user has spent and has available to spend ("points" are an ocPortal feature where users get rewarded for contributing to the site), we store these in variables then we use echo to send the user a HTML image. The image uses Google Chart API to automatically generate a pie chart showing these values. Here's the code:
/* This will use Google Chart API to draw a graph of the current
user's points availability. */
// First we get the current user ID
$userid = get_member();
// Now we get information about their points usage
// Load sources/points.php where the functions are defined
// Call the functions and store their values in some variables
$available = available_points($userid);
$used = points_used($userid);
// Now we create a pie chart of these results. The way we do this
// is to send the user a HTML image with the URL containing the
// data, such that Google can turn it into a pie chart.
// The details of how these URLs work can be found at
// A HTML image is written as <img src="url" alt="text" /> where
// url is the image's URL and text is a text alternative for
// those who browse in a text-only way.
// We start the image declaration
echo '<img src="';
// Then we set the start of the URL to Google's chart API
// Now we put all of our options at the end of the URL
echo 'cht=p3'; // We want a 3D pie chart
echo '&chtt=Your Points'; // The chart title
echo '&chco=0000FF'; // Make the chart blue
echo '&chs=300x150'; // Make it 300 pixels wide and 150 pixels tall
echo '&chd=t:'; // Start declaring the data
echo strval($used); // The amount of points used
echo ','; // Separator
echo strval($available); // The amount of unused points
echo '&chds=0,'; // The smallest data value
echo strval($available); // The largest data value
echo '&chl=Used|Available'; // Give labels to the data
// Now we give a text alternative and finish the declaration
echo '" alt="Your Points: ';
echo ' used, ';
echo ' available." />';
The parameters we add to the end of the image URL may seem incomprehensible, but they are described with plenty of examples on Google's site. I hope you have fun playing with variables, state and Google's chart generator. I've saved this to my ocPortal test installation as sources_custom/miniblocks/main_userpoints.php and here is a screenshot of the miniblock used in a news article, via the comcode [block]main_userpoints[/block] (after I'd gambled away some points in the points store ). Every user who views the article will see a chart of their own points.
Submitted by ChrisW