Migrating from PHP/FI 2.0 to PHP 3.0

About the incompatibilities in 3.0

PHP 3.0 is rewritten from the ground up. It has a proper parser that is much more robust and consistent than 2.0's. 3.0 is also significantly faster, and uses less memory. However, some of these improvements have not been possible without compatibility changes, both in syntax and functionality.

In addition, PHP's developers have tried to clean up both PHP's syntax and semantics in version 3.0, and this has also caused some incompatibilities. In the long run, we believe that these changes are for the better.

This chapter will try to guide you through the incompatibilities you might run into when going from PHP/FI 2.0 to PHP 3.0 and help you resolve them. New features are not mentioned here unless necessary.

A conversion program that can automatically convert your old PHP/FI 2.0 scripts exists. It can be found in the convertor subdirectory of the PHP 3.0 distribution. This program only catches the syntax changes though, so you should read this chapter carefully anyway.

Start/end tags

The first thing you probably will notice is that PHP's start and end tags have changed. The old <? > form has been replaced by three new possible forms:

P°φklad A-1. Migration: old start/end tags

<? echo "This is PHP/FI 2.0 code.\n"; >
As of version 2.0, PHP/FI also supports this variation:

P°φklad A-2. Migration: first new start/end tags

<? echo "This is PHP 3.0 code!\n"; ?>
Notice that the end tag now consists of a question mark and a greater-than character instead of just greater-than. However, if you plan on using XML on your server, you will get problems with the first new variant, because PHP may try to execute the XML markup in XML documents as PHP code. Because of this, the following variation was introduced:

P°φklad A-3. Migration: second new start/end tags

<?php echo "This is PHP 3.0 code!\n"; ?>
Some people have had problems with editors that don't understand the processing instruction tags at all. Microsoft FrontPage is one such editor, and as a workaround for these, the following variation was introduced as well:

P°φklad A-4. Migration: third new start/end tags

<script language="php">

  echo "This is PHP 3.0 code!\n";

</script>

if..endif syntax

The `alternative' way to write if/elseif/else statements, using if(); elseif(); else; endif; cannot be efficiently implemented without adding a large amount of complexity to the 3.0 parser. Because of this, the syntax has been changed:

P°φklad A-5. Migration: old if..endif syntax

if ($foo);
    echo "yep\n";
elseif ($bar);
    echo "almost\n";
else;
    echo "nope\n";
endif;

P°φklad A-6. Migration: new if..endif syntax

if ($foo):
    echo "yep\n";
elseif ($bar):
    echo "almost\n";
else:
    echo "nope\n";
endif;
Notice that the semicolons have been replaced by colons in all statements but the one terminating the expression (endif).

while syntax

Just like with if..endif, the syntax of while..endwhile has changed as well:

P°φklad A-7. Migration: old while..endwhile syntax

while ($more_to_come);
    ...
endwhile;

P°φklad A-8. Migration: new while..endwhile syntax

while ($more_to_come):
    ...
endwhile;

Varovßnφ

If you use the old while..endwhile syntax in PHP 3.0, you will get a never-ending loop.

Expression types

PHP/FI 2.0 used the left side of expressions to determine what type the result should be. PHP 3.0 takes both sides into account when determining result types, and this may cause 2.0 scripts to behave unexpectedly in 3.0.

Consider this example:

$a[0]=5;
$a[1]=7;

$key = key($a);
while ("" != $key) {
    echo "$keyn";
    next($a);
}

In PHP/FI 2.0, this would display both of $a's indices. In PHP 3.0, it wouldn't display anything. The reason is that in PHP 2.0, because the left argument's type was string, a string comparison was made, and indeed "" does not equal "0", and the loop went through. In PHP 3.0, when a string is compared with an integer, an integer comparison is made (the string is converted to an integer). This results in comparing atoi("") which is 0, and variablelist which is also 0, and since 0==0, the loop doesn't go through even once.

The fix for this is simple. Replace the while statement with:

while ((string)$key != "") {

Error messages have changed

PHP 3.0's error messages are usually more accurate than 2.0's were, but you no longer get to see the code fragment causing the error. You will be supplied with a file name and a line number for the error, though.

Short-circuited boolean evaluation

In PHP 3.0 boolean evaluation is short-circuited. This means that in an expression like (1 || test_me()), the function test_me() would not be executed since nothing can change the result of the expression after the 1.

This is a minor compatibility issue, but may cause unexpected side-effects.

Function true/false return values

Most internal functions have been rewritten so they return TRUE when successful and FALSE when failing, as opposed to 0 and -1 in PHP/FI 2.0, respectively. The new behaviour allows for more logical code, like $fp = fopen("/your/file") or fail("darn!");. Because PHP/FI 2.0 had no clear rules for what functions should return when they failed, most such scripts will probably have to be checked manually after using the 2.0 to 3.0 convertor.

P°φklad A-9. Migration from 2.0: return values, old code

$fp = fopen($file, "r");
if ($fp == -1);
    echo("Could not open $file for reading<br>\n");
endif;

P°φklad A-10. Migration from 2.0: return values, new code

$fp = @fopen($file, "r") or print("Could not open $file for reading<br>\n");

Other incompatibilities

P°φklad A-11. Migration from 2.0: concatenation for strings

echo "1" + "1";

In PHP 2.0 this would echo 11, in PHP 3.0 it would echo 2. Instead use:
echo "1"."1";
$a = 1;
$b = 1;
echo $a + $b;

This would echo 2 in both PHP 2.0 and 3.0.
$a = 1;
$b = 1;
echo $a.$b;
This will echo 11 in PHP 3.0.