Understanding variables in PHP
PHP is an interpreted language. This has many advantages, some of which you will soon learn to exploit. The first obvious advantage is that it saves you from the design-code-compile-test cycle -- any code that you write in your editor becomes instantly available. However, the most significant advantage is that you don't have worry about variables' types and how to manage them in memory. All memory that is allocated to a script is automatically taken back by PHP when the script finishes executing. Also, you can do many operations with variables without knowing their types. The code in Listing 1 works without a hitch in PHP, while it throws a plethora of error messages in the C and Java languages :
Listing 1. Sample PHP code with variables
To run the code after you have installed PHP, save the code in a .php file, put it on your Web server, and point your browser to it. An even better way is to install the CGI version of PHP. Then, you can run the script by typing the following command and replacing script-name by the file that contains your script on your shell or command prompt:
The code works because PHP is a loosely typed language. In plain English, you can forget variable types, assign strings to integers, and replace smaller strings by bigger ones effortlessly. This is not possible in languages like C. Internally, PHP stores the data that the variable holds separately from the types. Types are also stored, in a separate table. Whenever an expression involving different types comes along, PHP automatically determines what the programmer wants to do, changes the types in the tables, and evaluates the expression automatically.
Introducing a common glitch
Not worrying about types is good, but sometimes that can get you into real trouble. How? Here's a real-life example: I frequently have to pull content created on Windows-based PCs into Linux so it can be served on the Web. Windows-based file systems are case-insensitive when it comes to filenames. The filenames DefParser.php and defparser.php point to the same file on Windows. On a Linux operating system, they point to different files. You could promote filenames to some homogenous case, but the best practice would be to leave the case unaltered.
Solving the glitch
Suppose you want a function that checks whether a given file exists in a directory irrespective of the case. First, break down the task into simple steps. Breaking down code may sound ridiculous, but actually helps you focus on the code while writing it. Besides, rewriting the steps on paper is always easier than rewriting code:
- Get all filenames in the source directory
- Filter the . and the .. directories
- See if the target file exists in the directory
- If the file exists, get the file with the proper case
- Return a false if no names match
For reading the contents of a directory, you'll employ the
readdir() function. You can get more details about the function in the PHP Manual (see Resources). For now, you just need to know that readdir()
returns the names of all files in a given directory one by one on each
invocation. When all the filenames are listed, it returns a false.
You'll use a loop that terminates when
readdir() returns a false.
But is this enough? Remember, PHP is loosely typed, which means the integer zero and a false are treated as equal (even C treats zero and Boolean false as equivalent). The issue is not whether the code will work; imagine what might happen if the name of a file is 0! The script will terminate prematurely. You can use the following script (Listing 2) to confirm the zero and Boolean false equivalence:
Listing 2. Script to confirm zero and Boolean false equivalence
So what can you do? You know that PHP stores types internally and if you can access these types, the problems are solved. A Boolean false and an integer zero are obviously not equal.
PHP has a
gettype() function, but let's choose a simpler method here. You can use the === operator (yes, those are three equal signs). The difference is that
this operator compares both the values of the data and the types. If
you are wondering, there's a !== operator as well. These new operators and the
gettype() function are available in PHP 4 only. Listing 3 shows the complete code for the problem:
Lessons in observation
Rather than explain what each function in Listing 3 does, I encourage you to refer to the PHP Manual (see Resources). When you use unfamiliar functions, assumed arguments and return types can be another source of bugs. Instead of explaining the built-in function in PHP, I will explain some things that are less self-evident at first glance.
When the variable types involved in terminating conditions are different, it is important to use strong type checking by using the === and !== operators.
Code in parts
I could have written the entire script as a single function, but I have split the code into two functions. Remember the divide and conquer rule from the previous article? I did this precisely because each function has a different role to play. If you need to get the contents of a directory in some other script, now you'll have a handy implementation to use. I'd like you to consider something: visualize the entire script as one function and imagine the efforts required to debug, test, and reuse code.
Looping the right way
Now look at the
foreach loop and ask why not use a
for loop instead? Using a
loop would require that you know the number of items in the array -- an
additional step. Furthermore, it is possible to go out-of-bounds while
processing arrays in PHP. That is, trying to access the fifteenth
element of an array when it has only ten elements. PHP does give a
small warning, but I know of a few cases when a script has been
repeatedly run, the CPU activity has suddenly risen to 100% and the
server came spiraling down. I recommend that you abstain from using
for loops as much as possible.
An assertive if
Finally, I'd like you to have a look at that big
ifcondition used to omit the . and the .. directories in the
function. I can obviously go the traditional way and check a variable
against a constant. But in many of my own coding frenzies, I have often
missed an equal sign and wondered what went wrong later. Of course, PHP
doesn't complain because it assumes that I want to do assignment
instead of a comparison. When you compare a constant against a variable
and miss an equal sign, PHP throws error messages.