php-doc-en/appendices/migration4.xml
2004-08-13 04:34:35 +00:00

511 lines
19 KiB
XML

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- $Revision: 1.39 $ -->
<appendix id="migration4">
<title>Migrating from PHP 3 to PHP 4</title>
<section id='migration4.changes'>
<title>What has changed in PHP 4</title>
<para>
PHP 4 and the integrated Zend engine have greatly improved PHP's
performance and capabilities, but great care has been taken to
break as little existing code as possible. So migrating your code
from PHP 3 to 4 should be much easier than migrating from
PHP/FI 2 to PHP 3. A lot of existing PHP 3 code should be
ready to run without changes, but you should still know about the
few differences and take care to test your code before switching
versions in production environments. The following should give you
some hints about what to look for.
</para>
</section>
<section id="migration4.php4.with.php3">
<title>Running PHP 3 and PHP 4 concurrently</title>
<simpara>
Recent operating systems provide the ability to perform
versioning and scoping. This features make it possible to let
PHP 3 and PHP 4 run as concurrent modules in one Apache server.
</simpara>
<simpara>
This feature is known to work on the following platforms:
</simpara>
<itemizedlist>
<listitem><simpara>Linux with recent binutils (binutils 2.9.1.0.25 tested) </simpara></listitem>
<listitem><simpara>Solaris 2.5 or better</simpara></listitem>
<listitem><simpara>FreeBSD (3.2, 4.0 tested)</simpara></listitem>
</itemizedlist>
<para>
To enable it, configure PHP 3 and PHP 4 to use APXS
(<option role="configure">--with-apxs</option>) and the necessary
link extensions (<option role="configure">--enable-versioning</option>).
Otherwise, all standard installations instructions apply. For example:
<informalexample>
<programlisting role="shell">
<![CDATA[
$ ./configure \
--with-apxs=/apache/bin/apxs \
--enable-versioning \
--with-mysql \
--enable-track-vars
]]>
</programlisting>
</informalexample>
</para>
</section>
<section id="migration4.configuration">
<title>Migrating Configuration Files</title>
<para>
The global configuration file, <filename>php3.ini</filename>,
has changed its name to &php.ini;.
</para>
<para>
For the Apache configuration file, there are slightly more
changes. The MIME types recognized by the PHP module have
changed.
<informalexample>
<programlisting role="apache-conf">
<![CDATA[
application/x-httpd-php3 --> application/x-httpd-php
application/x-httpd-php3-source --> application/x-httpd-php-source
]]>
</programlisting>
</informalexample>
</para>
<para>
You can make your configuration files work with both versions
of PHP (depending on which one is currently compiled into the
server), using the following syntax:
<informalexample>
<programlisting role="apache-conf">
<![CDATA[
AddType application/x-httpd-php3 .php3
AddType application/x-httpd-php3-source .php3s
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
]]>
</programlisting>
</informalexample>
</para>
<simpara>
In addition, the PHP directive names for Apache have changed.
</simpara>
<para>
Starting with PHP 4.0, there are only four Apache directives
that relate to PHP:
<informalexample>
<programlisting role="apache-conf">
<![CDATA[
php_value [PHP directive name] [value]
php_flag [PHP directive name] [On|Off]
php_admin_value [PHP directive name] [value]
php_admin_flag [PHP directive name] [On|Off]
]]>
</programlisting>
</informalexample>
</para>
<simpara>
There are two differences between the Admin values and the non admin values:
</simpara>
<itemizedlist>
<listitem>
<simpara>
Admin values (or flags) can only appear in the server-wide Apache configuration
files (e.g., &httpd.conf;).
</simpara>
</listitem>
<listitem>
<simpara>
Standard values (or flags) cannot control certain PHP directives, for example:
&safemode; (if you could override safe mode settings in
&htaccess; files, it
would defeat &safemode;'s purpose). In contrast, Admin values can modify
the value of any PHP directive.
</simpara>
</listitem>
</itemizedlist>
<simpara>
To make the transition process easier, PHP 4 is bundled with scripts
that automatically convert your Apache configuration and
&htaccess; files
to work with both PHP 3 and PHP 4. These scripts do NOT convert the mime
type lines! You have to convert these yourself.
</simpara>
<para>
To convert your Apache configuration files, run the apconf-conv.sh
script (available in the scripts/apache/ directory). For example:
<informalexample>
<programlisting role="shell">
<![CDATA[
~/php4/scripts/apache:# ./apconf-conv.sh /usr/local/apache/conf/httpd.conf
]]>
</programlisting>
</informalexample>
</para>
<simpara>
Your original configuration file will be saved in httpd.conf.orig.
</simpara>
<para>
To convert your &htaccess; files, run the
<filename>aphtaccess-conv.sh</filename> script (available in
the <filename>scripts/apache/</filename> directory as well):
<informalexample>
<programlisting role="shell">
<![CDATA[
~/php4/scripts/apache:# find / -name .htaccess -exec ./aphtaccess-conv.sh {} \;
]]>
</programlisting>
</informalexample>
</para>
<simpara>
Likewise, your old &htaccess; files will be saved with
an .orig prefix.
</simpara>
<simpara>
The conversion scripts require awk to be installed.
</simpara>
</section>
<section id='migration4.parser'>
<title>Parser behavior</title>
<para>
Parsing and execution are now two completely separated steps, no
execution of a files code will happen until the complete file and
everything it requires has completely and successfully been
parsed.
</para>
<para>
One of the new requirements introduced with this split is that
required and included files now have to be syntactically
complete. You can no longer spread the different controlling parts
of a control structure across file boundaries. That is you cannot
start a <literal>for</literal> or <literal>while</literal> loop,
an <literal>if</literal> statement or a <literal>switch</literal>
block in one file and have the end of loop,
<literal>else</literal>, <literal>endif</literal>,
<literal>case</literal> or <literal>break</literal> statements in
a different file.
</para>
<para>
It still perfectly legal to include additional code within loops
or other control structures, only the controlling keywords and
corresponding curly braces <literal>{...}</literal> have to be
within the same compile unit (file or <function>eval</function>ed
string).
</para>
<para>
This should not harm too much as spreading code like this should be
considered as very bad style anyway.
</para>
<para>
Another thing no longer possible, though rarely seen in PHP 3
code is returning values from a required file. Returning a value
from an included file is still possible.
</para>
</section>
<section id='migration4.error-reporting'>
<title>Error reporting</title>
<section id='migration4.error-reporting.config'>
<title>Configuration changes</title>
<para>
With PHP 3 the error reporting level was set as a simple
numeric value formed by summing up the numbers related to
different error levels. Usual values were 15 for reporting all
errors and warnings or 7 for reporting everything but simple
notice messages reporting bad style and things like that.
</para>
<para>
PHP 4 has a larger set of error and warning levels and comes with a
configuration parser that now allows for symbolic constants to be used
for setting the intended behavior.
</para>
<para>
Error reporting level should now be configured by explicitly
taking away the warning levels you do not want to generate error
messages by x-oring them from the symbolic constant
<literal>E_ALL</literal>. Sounds complicated? Well, lets say you
want the error reporting system to report all but the simple
style warnings that are categorized by the symbolic constant
<literal>E_NOTICE</literal>. Then you'll put the following into
your &php.ini;: <literal>error_reporting =
E_ALL &amp; ~ ( E_NOTICE )</literal>. If you want to suppress
warnings too you add up the appropriate constant within the
braces using the binary or operator '|':
<literal>error_reporting= E_ALL &amp; ~ ( E_NOTICE | E_WARNING
)</literal>.
</para>
<warning>
<para>
When upgrading code or servers from PHP 3 to PHP 4 you should
check these settings and calls to
<function>error_reporting</function> or you might disable
reporting the new error types, especially E_COMPILE_ERROR. This
may lead to empty documents without any feedback of what happened
or where to look for the problem.
</para>
</warning>
<warning>
<para>
Using the old values 7 and 15 for setting up error reporting is
a very bad idea as this suppresses some of the newly added error
classes including parse errors. This may lead to very strange
behavior as scripts might no longer work without error messages
showing up anywhere.
</para>
<para>
This has lead to a lot of unreproducible bug reports in the
past where people reported script engine problems they were not
capable to track down while the &true; case was usually some
missing '}' in a required file that the parser was not able to
report due to a misconfigured error reporting system.
</para>
<para>
So checking your error reporting setup should be the first thing
to do whenever your scripts silently die. The Zend engine can
be considered mature enough nowadays to not cause this kind of
strange behavior.
</para>
</warning>
</section>
<section id='migration4.error-reporting.additions'>
<title>Additional warning messages</title>
<para>
A lot of existing PHP 3 code uses language constructs that
should be considered as very bad style as this code, while doing
the intended thing now, could easily be broken by changes in
other places. PHP 4 will output a lot of notice messages in
such situations where PHP 3 didn't. The easy fix is to just
turn off E_NOTICE messages, but it is usually a good idea to fix
the code instead.
</para>
<para>
The most common case that will now produce notice messages is the
use of unquoted string constants as array indices. Both PHP 3
and 4 will fall back to interpret these as strings if no
keyword or constant is known by that name, but whenever a
constant by that name had been defined anywhere else in the code
it might break your script. This can even become a security risk
if some intruder manages to redefine string constants in a way
that makes your script give him access rights he wasn't intended
to have. So PHP 4 will now warn you whenever you use unquoted
string constants as for example in
<literal>$_SERVER[REQUEST_METHOD]</literal>. Changing it
to <literal>$_SERVER['REQUEST_METHOD']</literal> will
make the parser happy and greatly improve the style and security
of your code.
</para>
<para>
Another thing PHP 4 will now tell you about is the use of
uninitialized variables or array elements.
</para>
</section>
</section>
<section id='migration4.initializers'>
<title>Initializers</title>
<para>
Static variable and class member initializers only accept scalar
values while in PHP 3 they accepted any valid expression. This
is, once again, due to the split between parsing and execution as
no code has yet been executed when the parser sees the
initializer.
</para>
<para>
For classes you should use constructors to initialize member
variables instead. For static variables anything but a simple
static value rarely makes sense anyway.
</para>
</section>
<section id='migration4.empty'>
<title><literal>empty("0")</literal></title>
<para>
The perhaps most controversial change in behavior has happened to the
behavior of the <function>empty</function>. A String containing
only the character '0' (zero) is now considered empty while it
wasn't in PHP 3.
</para>
<para>
This new behavior makes sense in web applications, with all input
fields returning strings even if numeric input is requested, and
with PHP's capabilities of automatic type conversion. But on the
other hand it might break your code in a rather subtle way,
leading to misbehavior that is hard to track down if you do not
know about what to look for.
</para>
</section>
<section id='migration4.missing'>
<title>Missing functions</title>
<para>
While PHP 4 comes with a lot of new features, functions and
extensions, you may still find some functions from version 3
missing. A small number of core functions has vanished because
they do not work with the new scheme of splitting parsing and
execution as introduced into 4 with the Zend engine. Other
functions and even complete extensions have become obsolete as
newer functions and extensions serve the same task better and/or
in a more general way. Some functions just simply haven't been
ported yet and finally some functions or extensions may be missing
due to license conflicts.
</para>
<section id='migration4.missing.concept'>
<title>Functions missing due to conceptual changes</title>
<para>
As PHP 4 now separates parsing from execution it is no longer
possible to change the behavior of the parser (now embedded in
the Zend engine) at runtime as parsing already happened by
then. So the function <function>short_tags</function> no longer
exists. You can still change the parsers behavior by setting
appropriate values in the &php.ini; file.
</para>
<para>
Another feature of PHP 3 that is not a part of PHP 4 is the bundled
debugging interface. There are third-party add-ons for the Zend engine
which add similar functionality.
</para>
</section>
<section id='migration4.deprecate'>
<title>Deprecate functions and extensions</title>
<para>
The Adabas and Solid database extensions are no more. Long live
the unified ODBC extension instead.
</para>
</section>
<section id='migration4.unset'>
<title>Changed status for <function>unset</function></title>
<para>
<function>unset</function>, although still available, is
implemented as a language construct rather than a function.
</para>
<para>
This does not have any consequences on the behavior of
<function>unset</function>, but testing for "unset" using
<function>function_exists</function> will return &false; as it would with
other language constructs that look like functions such as
<function>echo</function>.
</para>
<para>
Another more practical change is that it is no longer possible to
call <function>unset</function> indirectly, that is
<literal>$func="unset"; $func($somevar)</literal> won't work
anymore.
</para>
</section>
</section>
<section id='migration4.extensions'>
<title>PHP 3 extension</title>
<para>
Extensions written for PHP 3 will not work with PHP 4, neither as binaries
nor at the source level. It is not difficult to port extensions to PHP 4
if you have access to the original source. A detailed description of the
actual porting process is not part of this text.
</para>
</section>
<section id='migration4.strings'>
<title>Variable substitution in strings</title>
<para>
PHP 4 adds a new mechanism to variable substitution in
strings. You can now finally access object member variables and
elements from multidimensional arrays within strings.
</para>
<para>
To do so you have to enclose your variables with curly braces with
the dollar sign immediately following the opening brace:
<literal>{$...}</literal>
</para>
<para>
To embed the value of an object member variable into a string you
simply write <literal>"text {$obj-&gt;member} text"</literal> while
in PHP 3 you had to use something like <literal>"text
".$obj-&gt;member." text"</literal>.
</para>
<para>
This should lead to more readable code, while it may break
existing scripts written for PHP 3. But you can easily check for
this kind of problem by checking for the character combination
<literal>{$</literal> in your code and by replacing it with
<literal>\{$</literal> with your favorite search-and-replace
tool.
</para>
</section>
<section id='migration4.cookies'>
<title>Cookies</title>
<para>
PHP 3 had the bad habit of setting cookies in the reverse order
of the <function>setcookie</function> calls in your code. PHP 4
breaks with this habit and creates the cookie header lines in
exactly the same order as you set the cookies in the code.
</para>
<para>
This might break some existing code, but the old behaviour was so
strange to understand that it deserved a change to prevent further
problems in the future.
</para>
</section>
<section id='migration4.variables'>
<title>Handling of global variables</title>
<para>
While handling of global variables had the focus on to be easy in
PHP 3 and early versions of PHP 4, the focus has changed to be more
secure. While in PHP 3 the following example worked fine, in PHP 4 it
has to be unset(<literal>unset($GLOBALS["id"])</literal>);. This is
only one issue of global
variable handling. You should always have used <varname>$GLOBALS</varname>, with
newer versions of PHP 4 you are forced to do so in most cases.
Read more on this subject in the <link linkend="references.global">
<literal>global</literal> references section</link>.
</para>
<example>
<title>Migration of global variables</title>
<programlisting role="php">
<![CDATA[
<?php
$id = 1;
function test()
{
global $id;
unset($id);
}
test();
echo($id); // This will print out 1 in PHP 4
?>
]]>
</programlisting>
</example>
</section>
</appendix>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"../../manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->