PHP 3 and 4 Incompatibilities: A Closer Look
08/15/2000
by Edward Piou
Earlier this year, the PHP team released PHP 4.0, the latest major version of PHP: Hypertext Processor, a popular and useful server-side scripting system. The new version of PHP is supposed to be faster, more reliable, and just better all-around. In addition, it should be, for the most part, downwards-compatible with PHP 3. A quick list of incompatibilities (and there aren't many) is available at the PHP web site.
This article looks at some of the more interesting incompatibilities in-depth, and explores the type of code which you may have problems with if you try to move it from PHP 3 to PHP 4. I've included workarounds for several of the incompatibilities; some of which may be obvious, but some of which (hopefully) will help in any debugging you have to do.
This could be a big problem, depending on how often (and how) you check for the existence/truth value of variables which might have a string value of "0". For example, if you're checking to make sure the user chose one of the checkbox or radio values on a form with code like:
if ($check_val) {
process_val ($check_val);
}
else {
print "<br>Please check one of the boxes.\n";
}
and a valid value for the checkbox was "0", you'll have problems (since PHP passes the checkbox value through as a string). if ($check_val) will come out false, even though the value is set, and is not (really) false.
To fix this, use the isset() function, which returns true if a variable is set/exists, false otherwise:
if (isset ($check_val))
process_val ($check_val);
}
else {
...
I'm expecting this to be the biggest problem with moving my own code.
This setcookie() behavior is opposite that of PHP 3, in which calls to setcookie() were executed in reverse call order. This will be most important when you want to make sure you've deleted one cookie before inserting another. Say, for example, you've already (or might have already) set 19 cookies for a user from one particular server. If you try to set 2 more, theoretically, the user's browser may delete the oldest cookie you've given it (according to Netscape's cookie specification) rather than hold more than 20 cookies from your server. If you'd rather clear out some specific cookies before inserting, you could do this in PHP 3:
setcookie ("NewCookie2", $cookie_val2,time()+3600);
setcookie ("NewCookie1", $cookie_val1,time()+3600);
setcookie ("OldCookie2");
setcookie ("OldCookie1");
which would remove OldCookie1 (user now has 18 cookies), then OldCookie2 (17), then insert NewCookie1 (18), then NewCookie2 (19).
In PHP 4, you'd need to send the commands in reverse (or correct, depending on how you look at it) order for the same effect:
setcookie ("OldCookie1");
setcookie ("OldCookie2");
setcookie ("NewCookie1", $cookie_val1,time()+3600);
setcookie ("NewCookie2", $cookie_val2,time()+3600);
Probably not a problem, unless you and your coworkers are going crazy with setting cookies...
print "{$x}";
or
print "{$ }";
The content you're printing to a user's browser usually won't use bracketed variables; but if you generate your cascading style sheets or javascript functions with PHP you might have problems. For example, if you change the color of H1 tags based on some user-supplied or other variable:
<style type="text/css">
<!--
H1
<?PHP
Function user_css ($some_var) {
if ($some_var == 'r') {
return "color: red";
}
else {
return "color: blue";
}
}
$x = user_css ($some_var);
print "{$x}";
?>
-->
</style>
the print statement won't work correctly. One fix for this type of problem is to put the curly braces inside the variable; otherwise, changing the print line to:
print "\{$x}";
as the PHP team suggests, or alternatively
print "{" . $x . "}";
should work.
In PHP 4, the scope of a break or continue statement in an include()'d file or an eval()'d string is local to the file or string itself. Using such a statement to affect a loop outside the file or string won't work, and will generate an error.
In PHP 3, the scope was not limited in this way. With PHP 3, you could, for example, have code like this on a web page:
$files = return_list_of_relevant_files ($somevar);
for ($count = 0; $count < count($files); $count++) {
include ("$files[$count].inc"); /* pull in contents of file */
process_file ($files[$count]); /* maybe log the fact that the file was accessed? */
}
and in one of the included files have the text you want to display, plus a continue statement:
... text to be included ...
<?PHP continue; ?>
Why would you want to do this? Perhaps for certain files/cases, you don't need to process the file (maybe you log the fact that the file was accessed in most cases, and use the continue statement where logging isn't needed).
To get a similar result in PHP 4, you could set a variable instead of using continue:
... text to be included ...
<?PHP $continue_var = 1; ?>
and run the process_file function only if $continue_var is false:
$files = return_list_of_relevant_files ($somevar);
for ($count = 0; $count < count($files); $count++) {
$continue_var = 0;
include ("$files[$count].inc"); /* pull in contents of file */
if (! $continue_var) {
process_file ($files[$count]);
}
}
Since unset() was never documented as a function (so says the PHP team), nobody should have ever used it. Theoretically, though, you could have been using unset for something like the following case, where you need a variable to be unset before going through a loop, and wanted to use unset's return-value of 1 as a side-effect:
while (unset ($x)) {
if ($y) {
$x = set_x_value ($y);
}
if (isset ($x)) {
process_x_value ($x);
}
if (... some break-condition ...)
break;
}
}
To avoid getting a parse error, you can put the unset statement inside the loop, and put an always-true value in to keep the loop going:
while (1) {
unset ($x);
...
Here's a list of the remanining incompatibilities listed on the PHP site. I'm not going into as much detail with these, because - well, they seem a bit less interesting to me.
If you've got a large set of PHP 3 code to migrate, it'll definitely pay off to test your code after upgrading to PHP 4. Don't let the incompatibilities keep you from upgrading; gaining the speed and reliability of PHP 4 will be worth the hassle.
Edward Piou is an ahref.com producer and runs ep Productions, Inc., a development company based in the Washington, D.C. area.
This site copyright 1998-1999 ep Productions, Inc. Text of any articles is copyright of the author.