You are on page 1of 204

Part I.

Getting Started
What is PHP?
PHP (recursive acronym Ior "PHP: Hypertext Preprocessor") is a wideIy-used Open Source generaI-purpose
scripting Ianguage that is especiaIIy suited Ior Web deveIopment and can be embedded into HTML.
SimpIe answer, but what does that mean? An exampIe:
Example 1.1. An introductory example
<html>
<head>
<title>Example</title>
</head>
<body>
<?php
echo "Hi, I'm a PHP script!";
?>
</body>
</html>
Notice how this is diIIerent Irom a script written in other Ianguages Iike PerI or C -- instead oI writing a
program with Iots oI commands to output HTML, you write an HTML script with some embedded code to do
something (in this case, output some text). The PHP code is encIosed in speciaI start and end tags that aIIow
you to jump into and out oI "PHP mode".
What distinguishes PHP Irom something Iike cIient-side JavaScript is that the code is executed on the server.
II you were to have a script simiIar to the above on your server, the cIient wouId receive the resuIts oI running
that script, with no way oI determining what the underIying code may be. You can even conIigure your web
server to process aII your HTML IiIes with PHP, and then there's reaIIy no way that users can teII what you
have up your sIeeve.
The best things in using PHP are that it is extremeIy simpIe Ior a newcomer, but oIIers many advanced
Ieatures Ior a proIessionaI programmer. Don't be aIraid reading the Iong Iist oI PHP's Ieatures. You can jump
in, in a short time, and start writing simpIe scripts in a Iew hours.
AIthough PHP's deveIopment is Iocused on server-side scripting, you can do much more with it. Read on, and
see more in the What can PHP do? section, or go right to the introductory tutoriaI iI you are onIy interested in
web programming.
What can PHP do?
Anything. PHP is mainIy Iocused on server-side scripting, so you can do anything any other CGI program can
do, such as coIIect Iorm data, generate dynamic page content, or send and receive cookies. But PHP can do
much more.
There are three main areas where PHP scripts are used.
Server-side scripting. This is the most traditionaI and main target IieId Ior PHP. You need three things
to make this work. The PHP parser (CGI or server moduIe), a web server and a web browser. You need
to run the web server, with a connected PHP instaIIation. You can access the PHP program output with
a web browser, viewing the PHP page through the server. AII these can run on your home machine iI
you are just experimenting with PHP programming. See the instaIIation instructions section Ior more
inIormation.
Command Iine scripting. You can make a PHP script to run it without any server or browser. You onIy
need the PHP parser to use it this way. This type oI usage is ideaI Ior scripts reguIarIy executed using
cron (on *nix or Linux) or Task ScheduIer (on Windows). These scripts can aIso be used Ior simpIe
text processing tasks. See the section about Command Iine usage oI PHP Ior more inIormation.
Writing desktop appIications. PHP is probabIy not the very best Ianguage to create a desktop
appIication with a graphicaI user interIace, but iI you know PHP very weII, and wouId Iike to use some
advanced PHP Ieatures in your cIient-side appIications you can aIso use PHP-GTK to write such
programs. You aIso have the abiIity to write cross-pIatIorm appIications this way. PHP-GTK is an
extension to PHP, not avaiIabIe in the main distribution. II you are interested in PHP-GTK, visit its
own website.
PHP can be used on aII major operating systems, incIuding Linux, many Unix variants (incIuding HP-UX,
SoIaris and OpenBSD), MicrosoIt Windows, Mac OS X, RISC OS, and probabIy others. PHP has aIso support
Ior most oI the web servers today. This incIudes Apache, MicrosoIt Internet InIormation Server, PersonaI Web
Server, Netscape and iPIanet servers, OreiIIy Website Pro server, Caudium, Xitami, OmniHTTPd, and many
others. For the majority oI the servers PHP has a moduIe, Ior the others supporting the CGI standard, PHP can
work as a CGI processor.
So with PHP, you have the Ireedom oI choosing an operating system and a web server. Furthermore, you aIso
have the choice oI using proceduraI programming or object oriented programming, or a mixture oI them.
AIthough not every standard OOP Ieature is impIemented in PHP 4, many code Iibraries and Iarge
appIications (incIuding the PEAR Iibrary) are written onIy using OOP code. PHP 5 Iixes the OOP reIated
weaknesses oI PHP 4, and introduces a compIete object modeI.
With PHP you are not Iimited to output HTML. PHP's abiIities incIudes outputting images, PDF IiIes and even
FIash movies (using IibswI and Ming) generated on the IIy. You can aIso output easiIy any text, such as
XHTML and any other XML IiIe. PHP can autogenerate these IiIes, and save them in the IiIe system, instead
oI printing it out, Iorming a server-side cache Ior your dynamic content.
One oI the strongest and most signiIicant Ieatures in PHP is its support Ior a wide range oI databases. Writing
a database-enabIed web page is incredibIy simpIe. The IoIIowing databases are currentIy supported:
Adabas D InterBase PostgreSQL
dBase FrontBase SQLite
Empress mSQL SoIid
FiIePro (read-onIy) Direct MS-SQL Sybase
Hyperwave MySQL VeIocis
IBM DB2 ODBC Unix dbm
InIormix OracIe (OCI7 and OCI8)
Ingres Ovrimos
We aIso have a database abstraction extension (named PDO) aIIowing you to transparentIy use any database
supported by that extension. AdditionaIIy PHP supports ODBC, the Open Database Connection standard, so
you can connect to any other database supporting this worId standard.
PHP aIso has support Ior taIking to other services using protocoIs such as LDAP, IMAP, SNMP, NNTP, POP3,
HTTP, COM (on Windows) and countIess others. You can aIso open raw network sockets and interact using
any other protocoI. PHP has support Ior the WDDX compIex data exchange between virtuaIIy aII Web
programming Ianguages. TaIking about interconnection, PHP has support Ior instantiation oI Java objects and
using them transparentIy as PHP objects. You can aIso use our CORBA extension to access remote objects.
PHP has extremeIy useIuI text processing Ieatures, Irom the POSIX Extended or PerI reguIar expressions to
parsing XML documents. For parsing and accessing XML documents, PHP 4 supports the SAX and DOM
standards, and you can aIso use the XSLT extension to transIorm XML documents. PHP 5 standardizes aII the
XML extensions on the soIid base oI IibxmI2 and extends the Ieature set adding SimpIeXML and XMLReader
support.
At Iast but not Ieast, we have many other interesting extensions, the mnoGoSearch search engine Iunctions,
the IRC Gateway Iunctions, many compression utiIities (gzip, bz2, zip), caIendar conversion, transIation...
As you can see this page is not enough to Iist aII the Ieatures and beneIits PHP can oIIer. Read on in the
sections about instaIIing PHP, and see the Iunction reIerence part Ior expIanation oI the extensions mentioned
here.
Asimple tutorial
Here we wouId Iike to show the very basics oI PHP in a short, simpIe tutoriaI. This text onIy deaIs with
dynamic web page creation with PHP, though PHP is not onIy capabIe oI creating web pages. See the section
titIed What can PHP do Ior more inIormation.
PHP-enabIed web pages are treated just Iike reguIar HTML pages and you can create and edit them the same
way you normaIIy create reguIar HTML pages.
What do I need?
In this tutoriaI we assume that your server has activated support Ior PHP and that aII IiIes ending in .php are
handIed by PHP. On most servers, this is the deIauIt extension Ior PHP IiIes, but ask your server administrator
to be sure. II your server supports PHP, then you do not need to do anything. Just create your .php IiIes, put
them in your web directory and the server wiII automaticaIIy parse them Ior you. There is no need to compiIe
anything nor do you need to instaII any extra tooIs. Think oI these PHP-enabIed IiIes as simpIe HTML IiIes
with a whoIe new IamiIy oI magicaI tags that Iet you do aII sorts oI things. Most web hosts oIIer PHP support,
but iI your host does not, consider reading the PHP Links section Ior resources on Iinding PHP enabIed web
hosts.
Let us say you want to save precious bandwidth and deveIop IocaIIy. In this case, you wiII want to instaII a
web server, such as Apache, and oI course PHP. You wiII most IikeIy want to instaII a database as weII,
such as MySQL.
You can either instaII these individuaIIy or choose a simpIer way. Our manuaI has instaIIation instructions Ior
PHP (assuming you aIready have some web server set up). In case you have probIems with instaIIing PHP
yourseII, we wouId suggest you ask your questions on our instaIIation maiIing Iist. II you choose to go on
the simpIer route, then Iocate a pre-conIigured package Ior your operating system, which automaticaIIy
instaIIs aII oI these with just a Iew mouse cIicks. It is easy to setup a web server with PHP support on any
operating system, incIuding MacOSX, Linux and Windows. On Linux, you may Iind rpmIind and PBone
heIpIuI Ior Iocating RPMs. You may aIso want to visit apt-get to Iind
Your first PHP-enabled page
Create a IiIe named hello.php and put it in your web server's root directory (DOCUMENTROOT) with the
IoIIowing content:
Example 2.1. Our first PHP script: "#$$%&'"'
<html>
<head>
<title>PHP Test</title>
</head>
<body>
<?php echo '<p>Hello World</p>'; ?>
</body>
</html>
Use your browser to access the IiIe with your web server's URL, ending with the "/heIIo.php" IiIe reIerence.
When deveIoping IocaIIy this URL wiII be something Iike http.localhosthello.php or
http.127.0.0.1hello.php but this depends on the web server's conIiguration. II everything is conIigured
correctIy, this IiIe wiII be parsed by PHP and the IoIIowing output wiII be sent to your browser:
<html>
<head>
<title>PHP Test</title>
</head>
<body>
<p>Hello World</p>
</body>
</html>
This program is extremeIy simpIe and you reaIIy did not need to use PHP to create a page Iike this. AII it does
is dispIay: Hello horld using the PHP echo() statement. Note that the IiIe does not need to be executable or
speciaI in any way. The server Iinds out that this IiIe needs to be interpreted by PHP because you used the
".php" extension, which the server is conIigured to pass on to PHP. Think oI this as a normaI HTML IiIe
which happens to have a set oI speciaI tags avaiIabIe to you that do a Iot oI interesting things.
II you tried this exampIe and it did not output anything, it prompted Ior downIoad, or you see the whoIe IiIe as
text, chances are that the server you are on does not have PHP enabIed, or is not conIigured properIy. Ask your
administrator to enabIe it Ior you using the InstaIIation chapter oI the manuaI. II you are deveIoping IocaIIy,
aIso read the instaIIation chapter to make sure everything is conIigured properIy. Make sure that you access
the IiIe via http with the server providing you the output. II you just caII up the IiIe Irom your IiIe system, then
it wiII not be parsed by PHP. II the probIems persist anyway, do not hesitate to use one oI the many PHP
support options.
The point oI the exampIe is to show the speciaI PHP tag Iormat. In this exampIe we used ?php to indicate
the start oI a PHP tag. Then we put the PHP statement and IeIt PHP mode by adding the cIosing tag, ?. You
may jump in and out oI PHP mode in an HTML IiIe Iike this anywhere you want. For more detaiIs, read the
manuaI section on the basic PHP syntax.
A Note on Line Feeds: A Note on Line Feeds
Line Ieeds have IittIe meaning in HTML, however it is stiII a good idea to make your HTML Iook nice and
cIean by putting Iine Ieeds in. AIineIeed that IoIIows immediateIy aIter a cIosing ? wiII be removed by PHP.
This can be extremeIy useIuI when you are putting in many bIocks oI PHP or incIude IiIes containing PHP
that aren't supposed to output anything. At the same time it can be a bit conIusing. You can put a space aIter
the cIosing ? to Iorce a space and a Iine Ieed to be output, or you can put an expIicit Iine Ieed in the Iast
echo/print Irom within your PHP bIock.
A Note on Text Editors: ANote on Text Editors
There are many text editors and Integrated DeveIopment Environments (IDEs) that you can use to create, edit
and manage PHP IiIes. ApartiaI Iist oI these tooIs is maintained at PHP Editors List. II you wish to
recommend an editor, pIease visit the above page and ask the page maintainer to add the editor to the Iist.
Having an editor with syntax highIighting can be heIpIuI.
A Note on Word Processors: ANote on Word Processors
Word processors such as StarOIIice Writer, MicrosoIt Word and Abiword are not optimaI Ior editing PHP
IiIes. II you wish to use one Ior this test script, you must ensure that you save the IiIe as plain text or PHP wiII
not be abIe to read and execute the script.
A Note on Windows Notepad: A Note on Windows Notepad
II you are writing your PHP scripts using Windows Notepad, you wiII need to ensure that your IiIes are saved
with the .php extension. (Notepad adds a .txt extension to IiIes automaticaIIy unIess you take one oI the
IoIIowing steps to prevent it.) When you save the IiIe and are prompted to provide a name Ior the IiIe, pIace
the IiIename in quotes (i.e. "hello.php"). AIternativeIy, you can cIick on the 'Text Documents' drop-down
menu in the 'Save' diaIog box and change the setting to "AII FiIes". You can then enter your IiIename without
quotes.
Now that you have successIuIIy created a working PHP script, it is time to create the most Iamous PHP script!
Make a caII to the phpinIo() Iunction and you wiII see a Iot oI useIuI inIormation about your system and setup
such as avaiIabIe predeIined variabIes, Ioaded PHP moduIes, and conIiguration settings. Take some time and
review this important inIormation.
Example 2.2. Get system information from PHP
<?php phpinfo(); ?>
Something Useful
Let us do something more useIuI now. We are going to check what sort oI browser the visitor is using. For
that, we check the user agent string the browser sends as part oI the HTTP request. This inIormation is stored
in a variabIe. VariabIes aIways start with a doIIar-sign in PHP. The variabIe we are interested in right now is
SSERJER[HTTPUSERAGENT{.
Note: $SERVER is a speciaI reserved PHP variabIe that contains aII web server inIormation. It is known as a
supergIobaI. See the reIated manuaI page on supergIobaIs Ior more inIormation. These speciaI variabIes were
introduced in PHP 4.1.0. BeIore this time, we used the oIder SHTTP*JARS arrays instead, such as
SHTTPSERJERJARS. AIthough deprecated, these oIder variabIes stiII exist. (See aIso the note on oId code.)
To dispIay this variabIe, you can simpIy do:
Example 2.3. Printing a variable (Array element)
<?php
echo $_SERVER['HTTP_USER_AGENT'];
?>
A sampIe output oI this script may be:
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
There are many types oI variabIes avaiIabIe in PHP. In the above exampIe we printed an Array eIement.
Arrays can be very useIuI.
SSERJER is just one variabIe that PHP automaticaIIy makes avaiIabIe to you. AIist can be seen in the
Reserved VariabIes section oI the manuaI or you can get a compIete Iist oI them by Iooking at the output oI the
phpinIo() Iunction used in the exampIe in the previous section.
You can put muItipIe PHP statements inside a PHP tag and create IittIe bIocks oI code that do more than just a
singIe echo. For exampIe, iI you want to check Ior Internet ExpIorer you can do this:
Example 2.4. Example using control structures and functions
<?php
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) {
echo 'You are using Internet Explorer.<br />';
}
?>
A sampIe output oI this script may be:
You are using Internet Explorer.<br />
Here we introduce a coupIe oI new concepts. We have an iI statement. II you are IamiIiar with the basic
syntax used by the C Ianguage, this shouId Iook IogicaI to you. Otherwise, you shouId probabIy pick up an
introductory PHP book and read the Iirst coupIe oI chapters, or read the Language ReIerence part oI the
manuaI.
The second concept we introduced was the strpos() Iunction caII. strpos() is a Iunction buiIt into PHP which
searches a string Ior another string. In this case we are Iooking Ior MSIE (so-caIIed needIe) inside
SSERJER[HTTPUSERAGENT{ (so-caIIed haystack). II the needIe is Iound inside the haystack, the
Iunction returns the position oI the needIe reIative to the start oI the haystack. Otherwise, it returns FALSE. II it
does not return FALSE, the iI expression evaIuates to TRUE and the code within its braces} is executed.
Otherwise, the code is not run. FeeI Iree to create simiIar exampIes, with iI, eIse, and other Iunctions such as
strtoupper() and strIen(). Each reIated manuaI page contains exampIes too. II you are unsure how to use
Iunctions, you wiII want to read both the manuaI page on how to read a Iunction deIinition and the section
about PHP Iunctions.
We can take this a step Iurther and show how you can jump in and out oI PHP mode even in the middIe oI a
PHP bIock:
Example 2.5. Mixing both HTML and PHP modes
<?php
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) {
?>
<h3>strpos() must have returned non-false</h3>
<p>You are using Internet Explorer</p>
<?php
} else {
?>
<h3>strpos() must have returned false</h3>
<p>You are not using Internet Explorer</p>
<?php
}
?>
A sampIe output oI this script may be:
<h3>strpos() must have returned non-false</h3>
<p>You are using Internet Explorer</p>
Instead oI using a PHP echo statement to output something, we jumped out oI PHP mode and just sent straight
HTML. The important and powerIuI point to note here is that the IogicaI IIow oI the script remains intact.
OnIy one oI the HTML bIocks wiII end up getting sent to the viewer depending on the resuIt oI strpos(). In
other words, it depends on whether the string MSIE was Iound or not.
Dealing with Forms
One oI the most powerIuI Ieatures oI PHP is the way it handIes HTML Iorms. The basic concept that is
important to understand is that any Iorm eIement wiII automaticaIIy be avaiIabIe to your PHP scripts. PIease
read the manuaI section on VariabIes Irom outside oI PHP Ior more inIormation and exampIes on using Iorms
with PHP. Here is an exampIe HTML Iorm:
Example 2.6. Asimple HTML form
<form action="action.php" method="post">
<p>Your name: <input type="text" name="name" /></p>
<p>Your age: <input type="text" name="age" /></p>
<p><input type="submit" /></p>
</form>
There is nothing speciaI about this Iorm. It is a straight HTML Iorm with no speciaI tags oI any kind. When
the user IiIIs in this Iorm and hits the submit button, the action.php page is caIIed. In this IiIe you wouId write
something Iike this:
Example 2.7. Printing data from our form
Hi <?php echo htmlspecialchars($_POST['name']); ?>.
You are <?php echo (int)$_POST['age']; ?> years old.
A sampIe output oI this script may be:
Hi Joe. You are 22 years old.
Apart Irom the htmIspeciaIchars() and (int) parts, it shouId be obvious what this does. htmIspeciaIchars()
makes sure any characters that are speciaI in htmI are properIy encoded so peopIe can't inject HTML tags or
Javascript into your page. For the age IieId, since we know it is a number, we can just convert it to an integer
which wiII automaticaIIy get rid oI any stray characters. You can aIso have PHP do this Ior you automaticaIIy
by using the IiIter extension. The SPOST[name{ and SPOST[age{ variabIes are automaticaIIy set Ior you
by PHP. EarIier we used the SSERJER supergIobaI; above we just introduced the $POST supergIobaI which
contains aII POST data. Notice how the method oI our Iorm is POST. II we used the method GET then our
Iorm inIormation wouId Iive in the $GET supergIobaI instead. You may aIso use the $REQUEST
supergIobaI, iI you do not care about the source oI your request data. It contains the merged inIormation oI
GET, POST and COOKIE data. AIso see the importrequestvariabIes() Iunction.
You can aIso deaI with XForms input in PHP, aIthough you wiII Iind yourseII comIortabIe with the weII
supported HTML Iorms Ior quite some time. WhiIe working with XForms is not Ior beginners, you might be
interested in them. We aIso have a short introduction to handIing data received Irom XForms in our Ieatures
section.
Using old code with new versions of PHP
Now that PHP has grown to be a popuIar scripting Ianguage, there are a Iot oI pubIic repositories and Iibraries
containing code you can reuse. The PHP deveIopers have IargeIy tried to preserve backwards compatibiIity, so
a script written Ior an oIder version wiII run (ideaIIy) without changes in a newer version oI PHP. In practice,
some changes wiII usuaIIy be needed.
Two oI the most important recent changes that aIIect oId code are:
The deprecation oI the oId SHTTP*JARS arrays (which need to be indicated as gIobaI when used
inside a Iunction or method). The IoIIowing supergIobaI arrays were introduced in PHP 4.1.0. They
are: SGET, SPOST, SCOOKIE, SSERJER, SFILES, SENJ, SREQUEST, and SSESSION. The
oIder SHTTP*JARS arrays, such as SHTTPPOSTJARS, stiII exist as they have since PHP 3. As oI
PHP 5.0.0, the Iong PHP predeIined variabIe arrays may be disabIed with the registerIongarrays
directive.
ExternaI variabIes are no Ionger registered in the gIobaI scope by deIauIt. In other words, as oI PHP
4.2.0 the PHP directive registergIobaIs is off by deIauIt in php.ini. The preIerred method oI accessing
these vaIues is via the supergIobaI arrays mentioned above. OIder scripts, books, and tutoriaIs may reIy
on this directive being on. II it were on, Ior exampIe, one couId use Sid Irom the URL
http.www.example.comfoo.php?id42. Whether on or oII, SGET[id{ is avaiIabIe.
For more detaiIs on these changes, see the section on predeIined variabIes and Iinks therein.
What's next?
With your new knowIedge you shouId be abIe to understand most oI the manuaI and aIso the various exampIe
scripts avaiIabIe in the exampIe archives. You can aIso Iind other exampIes on the php.net websites in the
Iinks section: http://www.php.net/Iinks.php.
To view various sIide presentations that show more oI what PHP can do, see the PHP ConIerence MateriaI
Sites: http://conI.php.net/ and http://taIks.php.net/
Part lll. Language Reference
Chapter 10. Basic syntax
Escaping from HTML
When PHP parses a IiIe, it Iooks Ior opening and cIosing tags, which teII PHP to start and stop interpreting the
code between them. Parsing in this manner aIIows php to be embedded in aII sorts oI diIIerent documents, as
everything outside oI a pair oI opening and cIosing tags is ignored by the PHP parser. Most oI the time you
wiII see php embedded in HTML documents, as in this exampIe.
<p>This is going to be ignored.</p>
<?php echo 'While this is going to be parsed.'; ?>
<p>This will also be ignored.</p>
You can aIso use more advanced structures:
Example 10.1. Advanced escaping
<?php
if ($expression) {
?>
<strong>This is true.</strong>
<?php
} else {
?>
<strong>This is false.</strong>
<?php
}
?>
This works as expected, because when PHP hits the ?> cIosing tags, it simpIy starts outputting whatever it
Iinds (except Ior an immediateIy IoIIowing newIine - see instruction separation ) untiI it hits another opening
tag. The exampIe given here is contrived, oI course, but Ior outputting Iarge bIocks oI text, dropping out oI
PHP parsing mode is generaIIy more eIIicient than sending aII oI the text through echo() or print().
There are Iour diIIerent pairs oI opening and cIosing tags which can be used in php. Two oI those, ?php ?>
and script Ianguage"php"> /script>, are aIways avaiIabIe. The other two are short tags and ASP styIe tags,
and can be turned on and oII Irom the php.ini conIiguration IiIe. As such, whiIe some peopIe Iind short tags
and ASP styIe tags convenient, they are Iess portabIe, and generaIIy not recommended.
Note: AIso note that iI you are embedding PHP within XML or XHTML you wiII need to use the ?php ?>
tags to remain compIiant with standards.
Example 10.2. PHP Opening and Closing Tags
1. <?php echo 'if you want to serve XHTML or XML documents, do like this'; ?>
2. <script language="php">
echo 'some editors (like FrontPage) don\'t
like processing instructions';
</script>
3. <? echo 'this is the simplest, an SGML processing instruction'; ?>
<?= expression ?> This is a shortcut for "<? echo expression ?>"
4. <% echo 'You may optionally use ASP-style tags'; %>
<%= $variable; # This is a shortcut for "<% echo . . ." %>
WhiIe the tags seen in exampIes one and two are both aIways avaiIabIe, exampIe one is the most commonIy
used, and recommended, oI the two.
Short tags (exampIe three) are onIy avaiIabIe when they are enabIed via the shortopentag php.ini
conIiguration IiIe directive, or iI php was conIigured with the --enable-short-tags option.
Note: II you are using PHP 3 you may aIso enabIe short tags via the short_tags() Iunction. This is onlv
available in PHP 3!
ASP styIe tags (exampIe Iour) are onIy avaiIabIe when they are enabIed via the asptags php.ini conIiguration
IiIe directive.
Note: Support Ior ASP tags was added in 3.0.4.
Note: Using short tags shouId be avoided when deveIoping appIications or Iibraries that are meant Ior
redistribution, or depIoyment on PHP servers which are not under your controI, because short tags may not be
supported on the target server. For portabIe, redistributabIe code, be sure not to use short tags.
Instruction separation
As in C or PerI, PHP requires instructions to be terminated with a semicoIon at the end oI each statement. The
cIosing tag oI a bIock oI PHP code automaticaIIy impIies a semicoIon; you do not need to have a semicoIon
terminating the Iast Iine oI a PHP bIock. The cIosing tag Ior the bIock wiII incIude the immediateIy traiIing
newIine iI one is present.
<?php
echo 'This is a test';
?>
<?php echo 'This is a test' ?>
<?php echo 'We omitted the last closing tag';
Note: The cIosing tag oI a PHP bIock at the end oI a IiIe is optionaI, and in some cases omitting it is heIpIuI
when using incIude() or require(), so unwanted whitespace wiII not occur at the end oI IiIes, and you wiII stiII
be abIe to add headers to the response Iater. It is aIso handy iI you use output buIIering, and wouId not Iike to
see added unwanted whitespace at the end oI the parts generated by the incIuded IiIes.
Comments
PHP supports 'C', 'C' and Unix sheII-styIe (PerI styIe) comments. For exampIe:
<?php
echo 'This is a test'; // This is a one-line c++ style comment
/* This is a multi line comment
yet another line of comment */
echo 'This is yet another test';
echo 'One Final Test'; # This is a one-line shell-style comment
?>
The "one-Iine" comment styIes onIy comment to the end oI the Iine or the current bIock oI PHP code,
whichever comes Iirst. This means that HTML code aIter ... ? or ... ? WILL be printed: ?> breaks out
oI PHP mode and returns to HTML mode, and or cannot inIIuence that. II the asptags conIiguration
directive is enabIed, it behaves the same with and . However, the script tag doesn't break out
oI PHP mode in a one-Iine comment.
<h1>This is an <?php # echo 'simple';?> example.</h1>
<p>The header above will say 'This is an example'.</p>
'C' styIe comments end at the Iirst * encountered. Make sure you don't nest 'C' styIe comments. It is easy to
make this mistake iI you are trying to comment out a Iarge bIock oI code.
<?php
/*
echo 'This is a test'; /* This comment will cause a problem */
*/
?>
Types
Introduction
PHP supports eight primitive types.
Four scaIar types:
booIean
integer
IIoat (IIoating-point number, aka 'doubIe')
string
Two compound types:
array
object
And IinaIIy two speciaI types:
resource
NULL
This manuaI aIso introduces some pseudo-types Ior readabiIity reasons:
mixed
number
caIIback
And the pseudo-variabIe $....
You may aIso Iind some reIerences to the type "doubIe". Consider doubIe the same as IIoat, the two names
exist onIy Ior historic reasons.
The type oI a variabIe is usuaIIy not set by the programmer; rather, it is decided at runtime by PHP depending
on the context in which that variabIe is used.
Note: II you want to check out the type and vaIue oI a certain expression, use vardump().
II you simpIy want a human-readabIe representation oI the type Ior debugging, use gettype(). To check Ior a
certain type, do not use gettype(), but use the istype Iunctions. Some exampIes:
<?php
$a_bool = TRUE; // a boolean
$a_str = "foo"; // a string
$a_str2 = 'foo'; // a string
$an_int = 12; // an integer
echo gettype($a_bool); // prints out: boolean
echo gettype($a_str); // prints out: string
// If this is an integer, increment it by four
if (is_int($an_int)) {
$an_int += 4;
}
// If $bool is a string, print it out
// (does not print out anything)
if (is_string($a_bool)) {
echo "String: $a_bool";
}
?>
II you wouId Iike to Iorce a variabIe to be converted to a certain type, you may either cast the variabIe or use
the settype() Iunction on it.
Note that a variabIe may be evaIuated with diIIerent vaIues in certain situations, depending on what type it is
at the time. For more inIormation, see the section on Type JuggIing. AIso, you may be interested in viewing
the type comparison tabIes, as they show exampIes oI various type reIated comparisons.
Booleans
This is the easiest type. A booIean expresses a truth vaIue. It can be either TRUE or FALSE.
Note: The booIean type was introduced in PHP 4.
Syntax
To speciIy a booIean IiteraI, use either the keyword TRUE or FALSE. Both are case-insensitive.
<?php
$foo = True; // assign the value TRUE to $foo
?>
UsuaIIy you use some kind oI operator which returns a booIean vaIue, and then pass it on to a controI
structure.
<?php
// == is an operator which test
// equality and returns a boolean
if ($action == "show_version") {
echo "The version is 1.23";
}
// this is not necessary...
if ($show_separators == TRUE) {
echo "<hr>\n";
}
// ...because you can simply type
if ($show_separators) {
echo "<hr>\n";
}
?>
Converting to boolean
To expIicitIy convert a vaIue to booIean, use either the (bool) or the (boolean) cast. However, in most cases
you do not need to use the cast, since a vaIue wiII be automaticaIIy converted iI an operator, Iunction or
controI structure requires a booIean argument.
See aIso Type JuggIing.
When converting to booIean, the IoIIowing vaIues are considered FALSE:
the boolean FALSE itself
the integer 0 (zero)
the float 0.0 (zero)
the empty string, and the string "0"
an array with zero elements
an ob|ect with zero member variables (PHP 4 only)
the special type NULL (including unset variables)
5impleXML ob|ects created from empty tags
Every other value is considered TRUE (including any resource).
Warning
-1 is considered TRUE, Iike any other non-zero (whether negative or positive) number!
<?php
var_dump((bool) ""); // bool(false)
var_dump((bool) 1); // bool(true)
var_dump((bool) -2); // bool(true)
var_dump((bool) "foo"); // bool(true)
var_dump((bool) 2.3e5); // bool(true)
var_dump((bool) array(12)); // bool(true)
var_dump((bool) array()); // bool(false)
var_dump((bool) "false"); // bool(true)
?>
Integers
An integer is a number oI the set Z ..., -2, -1, 0, 1, 2, ...}.
See aIso: Arbitrary Iength integer / GMP, FIoating point numbers, and Arbitrary precision / BCMath
Syntax
Integers can be speciIied in decimaI (10-based), hexadecimaI (16-based) or octaI (8-based) notation,
optionaIIy preceded by a sign (- or ).
II you use the octaI notation, you must precede the number with a 0 (zero), to use hexadecimaI notation
precede the number with 0x.
Example 11.1. Integer literals
<?php
$a = 1234; // decimal number
$a = -123; // a negative number
$a = 0123; // octal number (equivalent to 83 decimal)
$a = 0x1A; // hexadecimal number (equivalent to 26 decimal)
?>
Formally the possible structure for integer literals is:
decimal : [1-9][0-9]*
| 0
hexadecimal : 0[xX][0-9a-fA-F]+
octal : 0[0-7]+
integer : [+-]?decimal
| [+-]?hexadecimal
| [+-]?octal
The size of an integer is platform-dependent, although a maximum value of about two
billion is the usual value (that's 32 bits signed). PHP does not support unsigned
integers. nteger size can be determined from PHP_INT_SIZE, maximum value from
PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.
Warning
II an invaIid digit is passed to octaI integer (i.e. 8 or 9), the rest oI the number is ignored.
Example 11.2. Octal weirdness
<?php
var_dump(01090); // 010 octal = 8 decimal
?>
Integer overflow
II you speciIy a number beyond the bounds oI the integer type, it wiII be interpreted as a IIoat instead. AIso, iI
you perIorm an operation that resuIts in a number beyond the bounds oI the integer type, a IIoat wiII be
returned instead.
<?php
$large_number = 2147483647;
var_dump($large_number);
// output: int(2147483647)
$large_number = 2147483648;
var_dump($large_number);
// output: float(2147483648)
// it's true also for hexadecimal specified integers between 2^31 and 2^32-1:
var_dump( 0xffffffff );
// output: float(4294967295)
// this doesn't go for hexadecimal specified integers above 2^32-1:
var_dump( 0x100000000 );
// output: int(2147483647)
$million = 1000000;
$large_number = 50000 * $million;
var_dump($large_number);
// output: float(50000000000)
?>
Warning
UnIortunateIy, there was a bug in PHP so that this does not aIways work correctIy when there are negative
numbers invoIved. For exampIe: when you do -50000 * Smillion, the resuIt wiII be -429496728. However,
when both operands are positive there is no probIem.
This is soIved in PHP 4.1.0.
There is no integer division operator in PHP. 12 yieIds the IIoat 0.5. You can cast the vaIue to an integer to
aIways round it downwards, or you can use the round() Iunction.
<?php
var_dump(25/7); // float(3.5714285714286)
var_dump((int) (25/7)); // int(3)
var_dump(round(25/7)); // float(4)
?>
Converting to integer
To expIicitIy convert a vaIue to integer, use either the (int) or the (integer) cast. However, in most cases you
do not need to use the cast, since a vaIue wiII be automaticaIIy converted iI an operator, Iunction or controI
structure requires an integer argument. You can aIso convert a vaIue to integer with the Iunction intvaI().
See aIso type-juggIing.
From booIeans
FALSE wiII yieId 0 (zero), and TRUE wiII yieId 1 (one).
From fIoating point numbers
When converting Irom IIoat to integer, the number wiII be rounded towards :ero.
II the IIoat is beyond the boundaries oI integer (usuaIIy - 2.15e9 231), the resuIt is undeIined, since the
IIoat hasn't got enough precision to give an exact integer resuIt. No warning, not even a notice wiII be issued
in this case!
Warning
Never cast an unknown Iraction to integer, as this can sometimes Iead to unexpected resuIts.
<?php
echo (int) ( (0.1+0.7) * 10 ); // echoes 7!
?>
5ee for more information the warning about float-precision.
From strings
See String conversion to numbers
From other types
Caution
Behaviour oI converting to integer is undeIined Ior other types. CurrentIy, the behaviour is the same as iI the
vaIue was Iirst converted to booIean. However, do not reIy on this behaviour, as it can change without notice.
Floating point numbers
FIoating point numbers (AKA "IIoats", "doubIes" or "reaI numbers") can be speciIied using any oI the
IoIIowing syntaxes:
<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
?>
Formally:
LNUM [0-9]+
DNUM ([0-9]*[\.]{LNUM}) | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM ( ({LNUM} | {DNUM}) [eE][+-]? {LNUM})
The size of a float is platform-dependent, although a maximum of -1.8e308 with a
precision of roughly 14 decimal digits is a common value (that's 64 bit EEE format).
Floating point precision
It is quite usuaI that simpIe decimaI Iractions Iike 0.1 or 0.7 cannot be converted into their internaI binary
counterparts without a IittIe Ioss oI precision. This can Iead to conIusing resuIts: Ior exampIe,
floor((0.10.7)*10) wiII usuaIIy return 7 instead oI the expected 8 as the resuIt oI the internaI representation
reaIIy being something Iike 7.9999999999....
This is reIated to the Iact that it is impossibIe to exactIy express some Iractions in decimaI notation with a
Iinite number oI digits. For instance, 13 in decimaI Iorm becomes 0.3333333. . ..
So never trust IIoating number resuIts to the Iast digit and never compare IIoating point numbers Ior equaIity.
II you reaIIy need higher precision, you shouId use the arbitrary precision math Iunctions or gmp Iunctions
instead.
Converting to float
For inIormation on when and how strings are converted to IIoats, see the section titIed String conversion to
numbers. For vaIues oI other types, the conversion is the same as iI the vaIue wouId have been converted to
integer and then to IIoat. See the Converting to integer section Ior more inIormation. As oI PHP 5, notice is
thrown iI you try to convert object to IIoat.
Strings
A string is series oI characters. In PHP, a character is the same as a byte, that is, there are exactIy 256 diIIerent
characters possibIe. This aIso impIies that PHP has no native support oI Unicode. See utI8encode() and
utI8decode() Ior some Unicode support.
Note: It is no probIem Ior a string to become very Iarge. There is no practicaI bound to the size oI strings
imposed by PHP, so there is no reason at aII to worry about Iong strings.
Syntax
A string IiteraI can be speciIied in three diIIerent ways.
single quoted
double quoted
heredoc syntax
SingIe quoted
The easiest way to speciIy a simpIe string is to encIose it in singIe quotes (the character ).
To speciIy a IiteraI singIe quote, you wiII need to escape it with a backsIash (), Iike in many other Ianguages.
II a backsIash needs to occur beIore a singIe quote or at the end oI the string, you need to doubIe it. Note that
iI you try to escape any other character, the backsIash wiII aIso be printed! So usuaIIy there is no need to
escape the backsIash itseII.
Note: In PHP 3, a warning wiII be issued at the ENOTICE IeveI when this happens.
Note: UnIike the two other syntaxes, variabIes and escape sequences Ior speciaI characters wiII not be
expanded when they occur in singIe quoted strings.
<?php
echo 'this is a simple string';
echo 'You can also have embedded newlines in
strings this way as it is
okay to do';
// Outputs: Arnold once said: "I'll be back"
echo 'Arnold once said: "I\'ll be back"';
// Outputs: You deleted C:\*.*?
echo 'You deleted C:\\*.*?';
// Outputs: You deleted C:\*.*?
echo 'You deleted C:\*.*?';
// Outputs: This will not expand: \n a newline
echo 'This will not expand: \n a newline';
// Outputs: Variables do not $expand $either
echo 'Variables do not $expand $either';
?>
DoubIe quoted
II the string is encIosed in doubIe-quotes ("), PHP understands more escape sequences Ior speciaI characters:
Table 11.1. Escaped characters
sequence meaning
\n linefeed (LF or 0x0A (10) in A5C)
\r carriage return (CR or 0x0D (13) in A5C)
\t horizontal tab (HT or 0x09 (9) in A5C)
\v vertical tab (VT or 0x0B (11) in A5C) (since PHP 5.2.5)
\| form feed (FF or 0x0C (12) in A5C) (since PHP 5.2.5)
\\ backslash
\$ dollar sign
\" double-quote
\j0-7]{J,3)
the sequence of characters matching the regular expression is a
character in octal notation
\xj0-9A-Fa-
|]{J,2)
the sequence of characters matching the regular expression is a
character in hexadecimal notation
Again, iI you try to escape any other character, the backsIash wiII be printed too! BeIore PHP 5.1.1, backsIash
in {Svar} hasn't been printed.
But the most important Ieature oI doubIe-quoted strings is the Iact that variabIe names wiII be expanded. See
string parsing Ior detaiIs.
Heredoc
Another way to deIimit strings is by using heredoc syntax (""). One shouId provide an identiIier (IoIIowed
by new Iine) aIter , then the string, and then the same identiIier to cIose the quotation.
The cIosing identiIier must begin in the Iirst coIumn oI the Iine. AIso, the identiIier used must IoIIow the same
naming ruIes as any other IabeI in PHP: it must contain onIy aIphanumeric characters and underscores, and
must start with a non-digit character or underscore.
Warning
It is very important to note that the Iine with the cIosing identiIier contains no other characters, except
possiblv a semicoIon (,). That means especiaIIy that the identiIier mav not be indented, and there may not be
any spaces or tabs aIter or beIore the semicoIon. It's aIso important to reaIize that the Iirst character beIore the
cIosing identiIier must be a newIine as deIined by your operating system. This is r on Macintosh Ior exampIe.
CIosing deIimiter (possibIy IoIIowed by a semicoIon) must be IoIIowed by a newIine too.
II this ruIe is broken and the cIosing identiIier is not "cIean" then it's not considered to be a cIosing identiIier
and PHP wiII continue Iooking Ior one. II in this case a proper cIosing identiIier is not Iound then a parse error
wiII resuIt with the Iine number being at the end oI the script.
It is not aIIowed to use heredoc syntax in initiaIizing cIass members. Use other string syntaxes instead.
Example 11.3. Invalid example
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
?>
Heredoc text behaves just Iike a doubIe-quoted string, without the doubIe-quotes. This means that you do not
need to escape quotes in your here docs, but you can stiII use the escape codes Iisted above. VariabIes are
expanded, but the same care must be taken when expressing compIex variabIes inside a heredoc as with
strings.
Example 11.4. Heredoc string quoting example
<?php
$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;
/* More complex example, with variables. */
class foo
{
var $foo;
var $bar;
function foo()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
?>
Note: Heredoc support was added in PHP 4.
VariabIe parsing
When a string is speciIied in doubIe quotes or with heredoc, variabIes are parsed within it.
There are two types oI syntax: a simpIe one and a compIex one. The simpIe syntax is the most common and
convenient. It provides a way to parse a variabIe, an array vaIue, or an object property.
The compIex syntax was introduced in PHP 4, and can be recognised by the curIy braces surrounding the
expression.
Simple syntax
II a doIIar sign (S) is encountered, the parser wiII greediIy take as many tokens as possibIe to Iorm a vaIid
variabIe name. EncIose the variabIe name in curIy braces iI you want to expIicitIy speciIy the end oI the name.
<?php
$beer = 'Heineken';
echo "$beer's taste is great"; // works, "'" is an invalid character for varnames
echo "He drank some $beers"; // won't work, 's' is a valid character for varnames
echo "He drank some ${beer}s"; // works
echo "He drank some {$beer}s"; // works
?>
SimiIarIy, you can aIso have an array index or an object property parsed. With array indices, the cIosing
square bracket ({) marks the end oI the index. For object properties the same ruIes appIy as to simpIe
variabIes, though with object properties there doesn't exist a trick Iike the one with variabIes.
<?php
// These examples are specific to using arrays inside of strings.
// When outside of a string, always quote your array string keys
// and do not use {braces} when outside of strings either.
// Let's show all errors
error_reporting(E_ALL);
$fruits = array('strawberry' => 'red', 'banana' => 'yellow');
// Works but note that this works differently outside string-quotes
echo "A banana is $fruits[banana].";
// Works
echo "A banana is {$fruits['banana']}.";
// Works but PHP looks for a constant named banana first
// as described below.
echo "A banana is {$fruits[banana]}.";
// Won't work, use braces. This results in a parse error.
echo "A banana is $fruits['banana'].";
// Works
echo "A banana is " . $fruits['banana'] . ".";
// Works
echo "This square is $square->width meters broad.";
// Won't work. For a solution, see the complex syntax.
echo "This square is $square->width00 centimeters broad.";
?>
For anything more compIex, you shouId use the compIex syntax.
Complex (curly) syntax
This isn't caIIed compIex because the syntax is compIex, but because you can incIude compIex expressions
this way.
In Iact, you can incIude any vaIue that is in the namespace in strings with this syntax. You simpIy write the
expression the same way as you wouId outside the string, and then incIude it in and }. Since you can't
escape '', this syntax wiII onIy be recognised when the $ is immediateIy IoIIowing the . (Use "\$" to get a
IiteraI "$"). Some exampIes to make it cIear:
<?php
// Let's show all errors
error_reporting(E_ALL);
$great = 'fantastic';
// Won't work, outputs: This is { fantastic}
echo "This is { $great}";
// Works, outputs: This is fantastic
echo "This is {$great}";
echo "This is ${great}";
// Works
echo "This square is {$square->width}00 centimeters broad.";
// Works
echo "This works: {$arr[4][3]}";
// This is wrong for the same reason as $foo[bar] is wrong
// outside a string. In other words, it will still work but
// because PHP first looks for a constant named foo, it will
// throw an error of level E_NOTICE (undefined constant).
echo "This is wrong: {$arr[foo][3]}";
// Works. When using multi-dimensional arrays, always use
// braces around arrays when inside of strings
echo "This works: {$arr['foo'][3]}";
// Works.
echo "This works: " . $arr['foo'][3];
echo "You can even write {$obj->values[3]->name}";
echo "This is the value of the var named $name: {${$name}}";
?>
Note: Functions and method caIIs work since PHP 5.
Note: Parsing variabIes within strings uses more memory than string concatenation. When writing a PHP
script in which memory usage is a concern, consider using the concatenation operator (.) rather than variabIe
parsing.
String access and modification by character
Characters within strings may be accessed and modiIied by speciIying the zero-based oIIset oI the desired
character aIter the string using square array-brackets Iike Sstr[42{ so think oI a string as an array oI
characters.
Note: They may aIso be accessed using braces Iike Sstr{42} Ior the same purpose. However, using square
array-brackets is preIerred because the braces} styIe is deprecated as oI PHP 6.
Example 11.5. Some string examples
<?php
// Get the first character of a string
$str = 'This is a test.';
$first = $str[0];
// Get the third character of a string
$third = $str[2];
// Get the last character of a string.
$str = 'This is still a test.';
$last = $str[strlen($str)-1];
// Modify the last character of a string
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
// Alternative method using {} is deprecated as of PHP 6
$third = $str{2};
?>
Note: Accessing by [{ or {} to variabIes oI other type siIentIy returns NULL.
Useful functions and operators
Strings may be concatenated using the '.' (dot) operator. Note that the '' (addition) operator wiII not work Ior
this. PIease see String operators Ior more inIormation.
There are a Iot oI useIuI Iunctions Ior string modiIication.
See the string Iunctions section Ior generaI Iunctions, the reguIar expression Iunctions Ior advanced
Iind&repIacing (in two tastes: PerI and POSIX extended).
There are aIso Iunctions Ior URL-strings, and Iunctions to encrypt/decrypt strings (mcrypt and mhash).
FinaIIy, iI you stiII didn't Iind what you're Iooking Ior, see aIso the character type Iunctions.
Converting to string
You can convert a vaIue to a string using the (string) cast, or the strvaI() Iunction. String conversion is
automaticaIIy done in the scope oI an expression Ior you where a string is needed. This happens when you use
the echo() or print() Iunctions, or when you compare a variabIe vaIue to a string. Reading the manuaI sections
on Types and Type JuggIing wiII make the IoIIowing cIearer. See aIso settype().
A booIean TRUE vaIue is converted to the string "1", the FALSE vaIue is represented as "" (empty string). This
way you can convert back and Iorth between booIean and string vaIues.
An integer or a IIoating point number (IIoat) is converted to a string representing the number with its digits
(incIuding the exponent part Ior IIoating point numbers). FIoating point numbers can be converted using the
exponentiaI notation (4.1E6).
Note: The decimaI point character is deIined in the script's IocaIe (category LCNUMERIC). See setIocaIe().
Arrays are aIways converted to the string "Arrav", so you cannot dump out the contents oI an array with
echo() or print() to see what is inside them. To view one eIement, you'd do something Iike echo Sarr[foo{.
See beIow Ior tips on dumping/viewing the entire contents.
Objects in PHP 4 are aIways converted to the string "Obfect". II you wouId Iike to print out the member
variabIe vaIues oI an object Ior debugging reasons, read the paragraphs beIow. II you wouId Iike to Iind out
the cIass name oI which an object is an instance oI, use getcIass(). As oI PHP 5, toString() method is used
iI appIicabIe.
Resources are aIways converted to strings with the structure "Resource id 1" where 1 is the unique number oI
the resource assigned by PHP during runtime. II you wouId Iike to get the type oI the resource, use
getresourcetype().
NULL is aIways converted to an empty string.
As you can see above, printing out the arrays, objects or resources does not provide you any useIuI
inIormation about the vaIues themseIves. Look at the Iunctions printr() and vardump() Ior better ways to
print out vaIues Ior debugging.
You can aIso convert PHP vaIues to strings to store them permanentIy. This method is caIIed seriaIization, and
can be done with the Iunction seriaIize(). You can aIso seriaIize PHP vaIues to XML structures, iI you have
WDDX support in your PHP setup.
String conversion to numbers
When a string is evaIuated as a numeric vaIue, the resuIting vaIue and type are determined as IoIIows.
The string wiII evaIuate as a IIoat iI it contains any oI the characters '.', 'e', or 'E'. Otherwise, it wiII evaIuate as
an integer.
The vaIue is given by the initiaI portion oI the string. II the string starts with vaIid numeric data, this wiII be
the vaIue used. Otherwise, the vaIue wiII be 0 (zero). VaIid numeric data is an optionaI sign, IoIIowed by one
or more digits (optionaIIy containing a decimaI point), IoIIowed by an optionaI exponent. The exponent is an
'e' or 'E' IoIIowed by one or more digits.
<?php
$foo = 1 + "10.5"; // $foo is float (11.5)
$foo = 1 + "-1.3e3"; // $foo is float (-1299)
$foo = 1 + "bob-1.3e3"; // $foo is integer (1)
$foo = 1 + "bob3"; // $foo is integer (1)
$foo = 1 + "10 Small Pigs"; // $foo is integer (11)
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2)
$foo = "10.0 pigs " + 1; // $foo is float (11)
$foo = "10.0 pigs " + 1.0; // $foo is float (11)
?>
For more inIormation on this conversion, see the Unix manuaI page Ior strtod(3).
II you wouId Iike to test any oI the exampIes in this section, you can cut and paste the exampIes and insert the
IoIIowing Iine to see Ior yourseII what's going on:
<?php
echo "\$foo==$foo; type is " . gettype ($foo) . "<br />\n";
?>
Do not expect to get the code oI one character by converting it to integer (as you wouId do in C Ior exampIe).
Use the Iunctions ord() and chr() to convert between charcodes and characters.
Arrays
An array in PHP is actuaIIy an ordered map. Amap is a type that maps values to kevs. This type is optimized
in severaI ways, so you can use it as a reaI array, or a Iist (vector), hashtabIe (which is an impIementation oI a
map), dictionary, coIIection, stack, queue and probabIy more. Because you can have another PHP array as a
vaIue, you can aIso quite easiIy simuIate trees.
ExpIanation oI those data structures is beyond the scope oI this manuaI, but you'II Iind at Ieast one exampIe
Ior each oI them. For more inIormation we reIer you to externaI Iiterature about this broad topic.
Syntax
Specifying with array()
An array can be created by the array() Ianguage-construct. It takes a certain number oI comma-separated key
value pairs.
array( key => value
, ...
)
// key may be an integer or string
// value may be any value
<?php
$arr = array("foo" => "bar", 12 => true);
echo $arr["foo"]; // bar
echo $arr[12]; // 1
?>
A kev may be either an integer or a string. II a key is the standard representation oI an integer, it wiII be
interpreted as such (i.e. "8" wiII be interpreted as 8, whiIe "08" wiII be interpreted as "08"). FIoats in kev are
truncated to integer. There are no diIIerent indexed and associative array types in PHP; there is onIy one array
type, which can both contain integer and string indices.
A vaIue can be oI any PHP type.
<?php
$arr = array("somearray" => array(6 => 5, 13 => 9, "a" => 42));
echo $arr["somearray"][6]; // 5
echo $arr["somearray"][13]; // 9
echo $arr["somearray"]["a"]; // 42
?>
II you do not speciIy a key Ior a given vaIue, then the maximum oI the integer indices is taken, and the new
key wiII be that maximum vaIue 1. II you speciIy a key that aIready has a vaIue assigned to it, that vaIue
wiII be overwritten.
<?php
// This array is the same as ...
array(5 => 43, 32, 56, "b" => 12);
// ...this array
array(5 => 43, 6 => 32, 7 => 56, "b" => 12);
?>
Warning
As oI PHP 4.3.0, the index generation behaviour described above has changed. Now, iI you append to an array
in which the current maximum key is negative, then the next key created wiII be zero (0). BeIore, the new
index wouId have been set to the Iargest existing key 1, the same as positive indices are.
Using TRUE as a key wiII evaIuate to integer 1 as key. Using FALSE as a key wiII evaIuate to integer 0 as key.
Using NULL as a key wiII evaIuate to the empty string. Using the empty string as key wiII create (or
overwrite) a key with the empty string and its vaIue; it is not the same as using empty brackets.
You cannot use arrays or objects as keys. Doing so wiII resuIt in a warning: Illegal offset tvpe.
Creating/modifying with square-bracket syntax
You can aIso modiIy an existing array by expIicitIy setting vaIues in it.
This is done by assigning vaIues to the array whiIe speciIying the key in brackets. You can aIso omit the key,
add an empty pair oI brackets ("[{") to the variabIe name in that case.
$arr[key] = value;
$arr[] = value;
// key may be an integer or string
// value may be any value
f $arr doesn't exist yet, it will be created. 5o this is also an alternative way to specify
an array. To change a certain value, |ust assign a new value to an element specified
with its key. f you want to remove a key/value pair, you need to unset() it.
<?php
$arr = array(5 => 1, 12 => 2);
$arr[] = 56; // This is the same as $arr[13] = 56;
// at this point of the script
$arr["x"] = 42; // This adds a new element to
// the array with key "x"
unset($arr[5]); // This removes the element from the array
unset($arr); // This deletes the whole array
?>
Note: As mentioned above, iI you provide the brackets with no key speciIied, then the maximum oI the
existing integer indices is taken, and the new key wiII be that maximum vaIue 1 . II no integer indices exist
yet, the key wiII be 0 (zero). II you speciIy a key that aIready has a vaIue assigned to it, that vaIue wiII be
overwritten.
Warning
As oI PHP 4.3.0, the index generation behaviour described above has changed. Now, iI you append to an array
in which the current maximum key is negative, then the next key created wiII be zero (0). BeIore, the new
index wouId have been set to the Iargest existing key 1, the same as positive indices are.
Note that the maximum integer key used Ior this need not currentlv exist in the arrav. It simpIy must have
existed in the array at some time since the Iast time the array was re-indexed. The IoIIowing exampIe
iIIustrates:
<?php
// Create a simple array.
$array = array(1, 2, 3, 4, 5);
print_r($array);
// Now delete every item, but leave the array itself intact:
foreach ($array as $i => $value) {
unset($array[$i]);
}
print_r($array);
// Append an item (note that the new key is 5, instead of 0 as you
// might expect).
$array[] = 6;
print_r($array);
// Re-index:
$array = array_values($array);
$array[] = 7;
print_r($array);
?>
The above exampIe wiII output:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
Array
(
)
Array
(
[5] => 6
)
Array
(
[0] => 6
[1] => 7
)
Useful functions
There are quite a Iew useIuI Iunctions Ior working with arrays. See the array Iunctions section.
Note: The unset() Iunction aIIows unsetting keys oI an array. Be aware that the array wiII NOT be reindexed.
II you onIy use "usuaI integer indices" (starting Irom zero, increasing by one), you can achieve the reindex
eIIect by using arrayvaIues().
<?php
$a = array(1 => 'one', 2 => 'two', 3 => 'three');
unset($a[2]);
/* will produce an array that would have been defined as
$a = array(1 => 'one', 3 => 'three');
and NOT
$a = array(1 => 'one', 2 =>'three');
*/
$b = array_values($a);
// Now $b is array(0 => 'one', 1 =>'three')
?>
The Ioreach controI structure exists speciIicaIIy Ior arrays. It provides an easy way to traverse an array.
Array do's and don'ts
Why is $foo[bar] wrong?
You shouId aIways use quotes around a string IiteraI array index. For exampIe, use $Ioo|'bar'] and not
$Ioo|bar]. But why is $Ioo|bar] wrong? You might have seen the IoIIowing syntax in oId scripts:
<?php
$foo[bar] = 'enemy';
echo $foo[bar];
// etc
?>
This is wrong, but it works. Then, why is it wrong? The reason is that this code has an
undefined constant (bar) rather than a string ('bar' - notice the quotes), and PHP may in
future define constants which, unfortunately for your code, have the same name. t
works because PHP automatically converts a bare string (an unquoted string which
does not correspond to any known symbol) into a string which contains the bare string.
For instance, if there is no defined constant named bar, then PHP will substitute in the
string 'bar' and use that.
Note: This does not mean to alwavs quote the key. You do not want to quote keys which are constants or
variabIes, as this wiII prevent PHP Irom interpreting them.
<?php
error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('html_errors', false);
// Simple array:
$array = array(1, 2);
$count = count($array);
for ($i = 0; $i < $count; $i++) {
echo "\nChecking $i: \n";
echo "Bad: " . $array['$i'] . "\n";
echo "Good: " . $array[$i] . "\n";
echo "Bad: {$array['$i']}\n";
echo "Good: {$array[$i]}\n";
}
?>
The above exampIe wiII output:
Checking 0:
Notice: Undefined index: $i in /path/to/script.html on line 9
Bad:
Good: 1
Notice: Undefined index: $i in /path/to/script.html on line 11
Bad:
Good: 1
Checking 1:
Notice: Undefined index: $i in /path/to/script.html on line 9
Bad:
Good: 2
Notice: Undefined index: $i in /path/to/script.html on line 11
Bad:
Good: 2
More exampIes to demonstrate this Iact:
<?php
// Let's show all errors
error_reporting(E_ALL);
$arr = array('fruit' => 'apple', 'veggie' => 'carrot');
// Correct
print $arr['fruit']; // apple
print $arr['veggie']; // carrot
// Incorrect. This works but also throws a PHP error of
// level E_NOTICE because of an undefined constant named fruit
//
// Notice: Use of undefined constant fruit - assumed 'fruit' in...
print $arr[fruit]; // apple
// Let's define a constant to demonstrate what's going on. We
// will assign value 'veggie' to a constant named fruit.
define('fruit', 'veggie');
// Notice the difference now
print $arr['fruit']; // apple
print $arr[fruit]; // carrot
// The following is okay as it's inside a string. Constants are not
// looked for within strings so no E_NOTICE error here
print "Hello $arr[fruit]"; // Hello apple
// With one exception, braces surrounding arrays within strings
// allows constants to be looked for
print "Hello {$arr[fruit]}"; // Hello carrot
print "Hello {$arr['fruit']}"; // Hello apple
// This will not work, results in a parse error such as:
// Parse error: parse error, expecting T_STRING' or T_VARIABLE' or T_NUM_STRING'
// This of course applies to using superglobals in strings as well
print "Hello $arr['fruit']";
print "Hello $_GET['foo']";
// Concatenation is another option
print "Hello " . $arr['fruit']; // Hello apple
?>
When you turn errorreporting() up to show E_NOTICE IeveI errors (such as setting it to E_ALL) then you wiII
see these errors. By deIauIt, errorreporting is turned down to not show them.
As stated in the syntax section, there must be an expression between the square brackets ('[' and '{'). That
means that you can write things Iike this:
<?php
echo $arr[somefunc($bar)];
?>
This is an example of using a function return value as the array index. PHP also knows
about constants, as you may have seen the E_* ones before.
<?php
$error_descriptions[E_ERROR] = "A fatal error has occured";
$error_descriptions[E_WARNING] = "PHP issued a warning";
$error_descriptions[E_NOTICE] = "This is just an informal notice";
?>
Note that E_ERROR is also a valid identifier, |ust like bar in the first example. But the
last example is in fact the same as writing:
<?php
$error_descriptions[1] = "A fatal error has occured";
$error_descriptions[2] = "PHP issued a warning";
$error_descriptions[8] = "This is just an informal notice";
?>
because E_ERROR equals J, etc.
As we aIready expIained in the above exampIes, Sfoo[bar{ stiII works but is wrong. It works, because bar is
due to its syntax expected to be a constant expression. However, in this case no constant with the name bar
exists. PHP now assumes that you meant bar IiteraIIy, as the string "bar", but that you Iorgot to write the
quotes.
So why is it bad then?
At some point in the Iuture, the PHP team might want to add another constant or keyword, or you may
introduce another constant into your appIication, and then you get in troubIe. For exampIe, you aIready cannot
use the words emptv and default this way, since they are speciaI reserved keywords.
Note: To reiterate, inside a doubIe-quoted string, it's vaIid to not surround array indexes with quotes so
"Sfoo[bar{" is vaIid. See the above exampIes Ior detaiIs on why as weII as the section on variabIe parsing in
strings.
Converting to array
For any oI the types: integer, IIoat, string, booIean and resource, iI you convert a vaIue to an array, you get an
array with one eIement (with index 0), which is the scaIar vaIue you started with.
II you convert an object to an array, you get the properties (member variabIes) oI that object as the array's
eIements. The keys are the member variabIe names with a Iew notabIe exceptions: private variabIes have the
cIass name prepended to the variabIe name; protected variabIes have a '*' prepended to the variabIe name.
These prepended vaIues have nuII bytes on either side. This can resuIt in some unexpected behaviour.
<?php
class A {
private $A; // This will become '\0A\0A'
}
class B extends A {
private $A; // This will become '\0B\0A'
public $AA; // This will become 'AA'
}
var_dump((array) new B());
?>
The above will appear to have two keys named 'AA', although one of them is actually
named '\0A\0A'.
II you convert a NULL vaIue to an array, you get an empty array.
Comparing
It is possibIe to compare arrays by arraydiII() and by Array operators.
Examples
The array type in PHP is very versatiIe, so here wiII be some exampIes to show you the IuII power oI arrays.
<?php
// this
$a = array( 'color' => 'red',
'taste' => 'sweet',
'shape' => 'round',
'name' => 'apple',
4 // key will be 0
);
// is completely equivalent with
$a['color'] = 'red';
$a['taste'] = 'sweet';
$a['shape'] = 'round';
$a['name'] = 'apple';
$a[] = 4; // key will be 0
$b[] = 'a';
$b[] = 'b';
$b[] = 'c';
// will result in the array array(0 => 'a' , 1 => 'b' , 2 => 'c'),
// or simply array('a', 'b', 'c')
?>
Example 11.6. Using array()
<?php
// Array as (property-)map
$map = array( 'version' => 4,
'OS' => 'Linux',
'lang' => 'english',
'short_tags' => true
);
// strictly numerical keys
$array = array( 7,
8,
0,
156,
-10
);
// this is the same as array(0 => 7, 1 => 8, ...)
$switching = array( 10, // key = 0
5 => 6,
3 => 7,
'a' => 4,
11, // key = 6 (maximum of integer-indices was 5)
'8' => 2, // key = 8 (integer!)
'02' => 77, // key = '02'
0 => 12 // the value 10 will be overwritten by 12
);
// empty array
$empty = array();
?>
Example 11.7. Collection
<?php
$colors = array('red', 'blue', 'green', 'yellow');
foreach ($colors as $color) {
echo "Do you like $color?\n";
}
?>
The above exampIe wiII output:
Do you like red?
Do you like blue?
Do you like green?
Do you like yellow?
Changing vaIues oI the array directIy is possibIe since PHP 5 by passing them as reIerence. Prior versions
need workaround:
Example 11.8. Collection
<?php
// PHP 5
foreach ($colors as &$color) {
$color = strtoupper($color);
}
unset($color); /* ensure that following writes to
$color will not modify the last array element */
// Workaround for older versions
foreach ($colors as $key => $color) {
$colors[$key] = strtoupper($color);
}
print_r($colors);
?>
The above exampIe wiII output:
Array
(
[0] => RED
[1] => BLUE
[2] => GREEN
[3] => YELLOW
)
This exampIe creates a one-based array.
Example 11.9. One-based index
<?php
$firstquarter = array(1 => 'January', 'February', 'March');
print_r($firstquarter);
?>
The above exampIe wiII output:
Array
(
[1] => 'January'
[2] => 'February'
[3] => 'March'
)
Example 11.10. Filling an array
<?php
// fill an array with all items from a directory
$handle = opendir('.');
while (false !== ($file = readdir($handle))) {
$files[] = $file;
}
closedir($handle);
?>
Arrays are ordered. You can aIso change the order using various sorting Iunctions. See the array Iunctions
section Ior more inIormation. You can count the number oI items in an array using the count() Iunction.
Example 11.11. Sorting an array
<?php
sort($files);
print_r($files);
?>
Because the vaIue oI an array can be anything, it can aIso be another array. This way you can make recursive
and muIti-dimensionaI arrays.
Example 11.12. Recursive and multi-dimensional arrays
<?php
$fruits = array ( "fruits" => array ( "a" => "orange",
"b" => "banana",
"c" => "apple"
),
"numbers" => array ( 1,
2,
3,
4,
5,
6
),
"holes" => array ( "first",
5 => "second",
"third"
)
);
// Some examples to address values in the array above
echo $fruits["holes"][5]; // prints "second"
echo $fruits["fruits"]["a"]; // prints "orange"
unset($fruits["holes"][0]); // remove "first"
// Create a new multi-dimensional array
$juices["apple"]["green"] = "good";
?>
You shouId be aware that array assignment aIways invoIves vaIue copying. It aIso means that the internaI
array pointer used by current() and simiIar Iunctions is reset. You need to use the reIerence operator to copy an
array by reIerence.
<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
// $arr1 is still array(2, 3)
$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same
?>
Objects
Object Initialization
To initiaIize an object, you use the new statement to instantiate the object to a variabIe.
<?php
class foo
{
function do_foo()
{
echo "Doing foo.";
}
}
$bar = new foo;
$bar->do_foo();
?>
For a IuII discussion, pIease read the section CIasses and Objects.
Converting to object
II an object is converted to an object, it is not modiIied. II a vaIue oI any other type is converted to an object, a
new instance oI the stdClass buiIt in cIass is created. II the vaIue was NULL, the new instance wiII be empty.
Array converts to an object with properties named by array keys and with corresponding vaIues. For any other
vaIue, a member variabIe named scalar wiII contain the vaIue.
<?php
$obj = (object) 'ciao';
echo $obj->scalar; // outputs 'ciao'
?>
Resource
A resource is a speciaI variabIe, hoIding a reIerence to an externaI resource. Resources are created and used by
speciaI Iunctions. See the appendix Ior a Iisting oI aII these Iunctions and the corresponding resource types.
Note: The resource type was introduced in PHP 4
See aIso getresourcetype().
Converting to resource
As resource types hoId speciaI handIers to opened IiIes, database connections, image canvas areas and the
Iike, you cannot convert any vaIue to a resource.
Freeing resources
Due to the reIerence-counting system introduced with PHP 4's Zend Engine, it is automaticaIIy detected when
a resource is no Ionger reIerred to (just Iike Java). When this is the case, aII resources that were in use Ior this
resource are made Iree by the garbage coIIector. For this reason, it is rareIy ever necessary to Iree the memory
manuaIIy by using some IreeresuIt Iunction.
Note: Persistent database Iinks are speciaI, they are not destroyed by the garbage coIIector. See aIso the
section about persistent connections.
NULL
The speciaI NULL vaIue represents that a variabIe has no vaIue. NULL is the onIy possibIe vaIue oI type NULL.
Note: The nuII type was introduced in PHP 4.
A variabIe is considered to be NULL iI
it has been assigned the constant NULL.
it has not been set to any vaIue yet.
it has been unset().
Syntax
There is onIy one vaIue oI type NULL, and that is the case-insensitive keyword NULL.
<?php
$var = NULL;
?>
See aIso isnuII() and unset().
Pseudo-types and variables used in this
documentation
mixed
mixed indicates that a parameter may accept muItipIe (but not necessariIy aII) types.
gettype() Ior exampIe wiII accept aII PHP types, whiIe strrepIace() wiII accept strings and arrays.
number
number indicates that a parameter can be either integer or IIoat.
callback
Some Iunctions Iike caIIuserIunc() or usort() accept user deIined caIIback Iunctions as a parameter.
CaIIback Iunctions can not onIy be simpIe Iunctions but aIso object methods incIuding static cIass methods.
A PHP Iunction is simpIy passed by its name as a string. You can pass any buiIt-in or user deIined Iunction
with the exception oI array(), echo(), empty(), evaI(), exit(), isset(), Iist(), print() and unset().
A method oI an instantiated object is passed as an array containing an object as the eIement with index 0 and a
method name as the eIement with index 1.
Static cIass methods can aIso be passed without instantiating an object oI that cIass by passing the cIass name
instead oI an object as the eIement with index 0.
Apart Irom common user-deIined Iunction, createIunction() can be used to create an anonymous caIIback
Iunction.
Example 11.13. Callback function examples
<?php
// An example callback function
function my_callback_function() {
echo 'hello world!';
}
// An example callback method
class MyClass {
function myCallbackMethod() {
echo 'Hello World!';
}
}
// Type 1: Simple callback
call_user_func('my_callback_function');
// Type 2: Static class method call
call_user_func(array('MyClass', 'myCallbackMethod'));
// Type 3: Object method call
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));
?>
Note: In PHP4, you wiII have to use a reIerence to create a caIIback that points to the actuaI object, and not a
copy oI it. For more detaiIs, see ReIerences ExpIained.
void
void in return type means that the return vaIue is useIess. void in parameters Iist means that the Iunction
doesn't accept any parameters.
...
$... in Iunction prototypes means and so on. This variabIe name is used when a Iunction can take an endIess
number oI arguments.
Type 1uggling
PHP does not require (or support) expIicit type deIinition in variabIe decIaration; a variabIe's type is
determined by the context in which that variabIe is used. That is to say, iI you assign a string vaIue to variabIe
$var, $var becomes a string. II you then assign an integer vaIue to $var, it becomes an integer.
An exampIe oI PHP's automatic type conversion is the addition operator ''. II any oI the operands is a IIoat,
then aII operands are evaIuated as IIoats, and the resuIt wiII be a IIoat. Otherwise, the operands wiII be
interpreted as integers, and the resuIt wiII aIso be an integer. Note that this does NOT change the types oI the
operands themseIves; the onIy change is in how the operands are evaIuated.
<?php
$foo = "0"; // $foo is string (ASCII 48)
$foo += 2; // $foo is now an integer (2)
$foo = $foo + 1.3; // $foo is now a float (3.3)
$foo = 5 + "10 Little Piggies"; // $foo is integer (15)
$foo = 5 + "10 Small Pigs"; // $foo is integer (15)
?>
II the Iast two exampIes above seem odd, see String conversion to numbers.
II you wish to Iorce a variabIe to be evaIuated as a certain type, see the section on Type casting. II you wish to
change the type oI a variabIe, see settype().
II you wouId Iike to test any oI the exampIes in this section, you can use the vardump() Iunction.
Note: The behaviour oI an automatic conversion to array is currentIy undeIined.
AIso, because PHP supports indexing into strings via oIIsets using the same syntax as array indexing, the
IoIIowing exampIe hoIds true Ior aII PHP versions:
<?php
$a = 'car'; // $a is a string
$a[0] = 'b'; // $a is still a string
echo $a; // bar
?>
See the section titIed String access by character Ior more inIormation.
Type Casting
Type casting in PHP works much as it does in C: the name oI the desired type is written in parentheses beIore
the variabIe which is to be cast.
<?php
$foo = 10; // $foo is an integer
$bar = (boolean) $foo; // $bar is a boolean
?>
The casts aIIowed are:
(int), (integer) - cast to integer
(bool), (boolean) - cast to boolean
(float), (double), (real) - cast to float
(string) - cast to string
(binary) - cast to binary string (PHP 6)
(array) - cast to array
(ob|ect) - cast to ob|ect
(binary) casting and b preIix Iorward support was added in PHP 5.2.1
Note that tabs and spaces are aIIowed inside the parentheses, so the IoIIowing are IunctionaIIy equivaIent:
<?php
$foo = (int) $bar;
$foo = ( int ) $bar;
?>
Casting a IiteraI strings and variabIes to binary strings:
<?php
$binary = (binary)$string;
$binary = b"binary string";
?>
Note: Instead oI casting a variabIe to string, you can aIso encIose the variabIe in doubIe quotes.
<?php
$foo = 10; // $foo is an integer
$str = "$foo"; // $str is a string
$fst = (string) $foo; // $fst is also a string
// This prints out that "they are the same"
if ($fst === $str) {
echo "they are the same";
}
?>
It may not be obvious exactIy what wiII happen when casting between certain types. For more inIo, see these
sections:
Chapter 12. Variables
Basics
VariabIes in PHP are represented by a doIIar sign IoIIowed by the name oI the variabIe. The variabIe name is
case-sensitive.
VariabIe names IoIIow the same ruIes as other IabeIs in PHP. A vaIid variabIe name starts with a Ietter or
underscore, IoIIowed by any number oI Ietters, numbers, or underscores. As a reguIar expression, it wouId be
expressed thus: '|a-zA-Z\x7I-\xII]|a-zA-Z0-9\x7I-\xII]*'
Note: For our purposes here, a Ietter is a-z, A-Z, and the ASCII characters Irom 127 through 255 (0x7I-0xII).
Note: Sthis is a speciaI variabIe that can't be assigned.
Tip
You may aIso want to take a Iook at the Appendix T, Userland Naming Guide.
For inIormation on variabIe reIated Iunctions, see the VariabIe Functions ReIerence.
<?php
$var = 'Bob';
$Var = 'Joe';
echo "$var, $Var"; // outputs "Bob, Joe"
$4site = 'not yet'; // invalid; starts with a number
$_4site = 'not yet'; // valid; starts with an underscore
$tyte = 'mansikka'; // valid; '' is (Extended) ASCII 228.
?>
In PHP 3, variabIes are aIways assigned by vaIue. That is to say, when you assign an expression to a variabIe,
the entire vaIue oI the originaI expression is copied into the destination variabIe. This means, Ior instance, that
aIter assigning one variabIe's vaIue to another, changing one oI those variabIes wiII have no eIIect on the
other. For more inIormation on this kind oI assignment, see the chapter on Expressions.
As oI PHP 4, PHP oIIers another way to assign vaIues to variabIes: assign by reIerence. This means that the
new variabIe simpIy reIerences (in other words, "becomes an aIias Ior" or "points to") the originaI variabIe.
Changes to the new variabIe aIIect the originaI, and vice versa.
To assign by reIerence, simpIy prepend an ampersand (&) to the beginning oI the variabIe which is being
assigned (the source variabIe). For instance, the IoIIowing code snippet outputs 'My name is Bob' twice:
<?php
$foo = 'Bob'; // Assign the value 'Bob' to $foo
$bar = &$foo; // Reference $foo via $bar.
$bar = "My name is $bar"; // Alter $bar...
echo $bar;
echo $foo; // $foo is altered too.
?>
One important thing to note is that onIy named variabIes may be assigned by reIerence.
<?php
$foo = 25;
$bar = &$foo; // This is a valid assignment.
$bar = &(24 * 7); // Invalid; references an unnamed expression.
function test()
{
return 25;
}
$bar = &test(); // Invalid.
?>
It is not necessary to initiaIize variabIes in PHP however it is a very good practice. UninitiaIized variabIes
have a deIauIt vaIue oI their type - FALSE, zero, empty string or an empty array.
Example 12.1. Default values of uninitialized variables
<?php
echo ($unset_bool ? "true" : "false"); // false
$unset_int += 25; // 0 + 25 => 25
echo $unset_string . "abc"; // "" . "abc" => "abc"
$unset_array[3] = "def"; // array() + array(3 => "def") => array(3 => "def")
?>
ReIying on the deIauIt vaIue oI an uninitiaIized variabIe is probIematic in the case oI incIuding one IiIe into
another which uses the same variabIe name. It is aIso a major security risk with registergIobaIs turned on.
ENOTICE IeveI error is issued in case oI working with uninitiaIized variabIes, however not in the case oI
appending eIements to the uninitiaIized array. isset() Ianguage construct can be used to detect iI a variabIe has
been aIready initiaIized.
Predefined variables
PHP provides a Iarge number oI predeIined variabIes to any script which it runs. Many oI these variabIes,
however, cannot be IuIIy documented as they are dependent upon which server is running, the version and
setup oI the server, and other Iactors. Some oI these variabIes wiII not be avaiIabIe when PHP is run on the
command Iine. For a Iisting oI these variabIes, pIease see the section on Reserved PredeIined VariabIes.
Warning
In PHP 4.2.0 and Iater, the deIauIt vaIue Ior the PHP directive registergIobaIs is off. This is a major change in
PHP. Having registergIobaIs off aIIects the set oI predeIined variabIes avaiIabIe in the gIobaI scope. For
exampIe, to get DOCUMENTROOT you'II use SSERJER[DOCUMENTROOT{ instead oI
SDOCUMENTROOT, or SGET[id{ Irom the URL http.www.example.comtest.php?id3 instead oI Sid,
or SENJ[HOME{ instead oI SHOME.
For reIated inIormation on this change, read the conIiguration entry Ior registergIobaIs, the security chapter
on Using Register GIobaIs , as weII as the PHP 4.1.0 and 4.2.0 ReIease Announcements.
Using the avaiIabIe PHP Reserved PredeIined VariabIes, Iike the supergIobaI arrays, is preIerred.
From version 4.1.0 onward, PHP provides an additionaI set oI predeIined arrays containing variabIes Irom the
web server (iI appIicabIe), the environment, and user input. These new arrays are rather speciaI in that they are
automaticaIIy gIobaI--i.e., automaticaIIy avaiIabIe in every scope. For this reason, they are oIten known as
"supergIobaIs". (There is no mechanism in PHP Ior user-deIined supergIobaIs.) The supergIobaIs are Iisted
beIow; however, Ior a Iisting oI their contents and Iurther discussion on PHP predeIined variabIes and their
natures, pIease see the section Reserved PredeIined VariabIes. AIso, you'II notice how the oIder predeIined
variabIes (SHTTP*JARS) stiII exist. As oI PHP 5.0.0, the Iong PHP predeIined variabIe arrays may be
disabIed with the registerIongarrays directive.
Variable variables: SupergIobaIs cannot be used as variabIe variabIes inside Iunctions or cIass methods.
Note: Even though both the supergIobaI and HTTP*VARS can exist at the same time; they are not
identicaI, so modiIying one wiII not change the other.
II certain variabIes in variabIesorder are not set, their appropriate PHP predeIined arrays are aIso IeIt empty.
PHP Superglobals
$GLOBALS
Contains a reIerence to every variabIe which is currentIy avaiIabIe within the gIobaI scope oI the
script. The keys oI this array are the names oI the gIobaI variabIes. SGLOBALS has existed since PHP
3.
$SERVER
VariabIes set by the web server or otherwise directIy reIated to the execution environment oI the
current script. AnaIogous to the oId SHTTPSERJERJARS array (which is stiII avaiIabIe, but
deprecated).
$GET
VariabIes provided to the script via URL query string. AnaIogous to the oId SHTTPGETJARS array
(which is stiII avaiIabIe, but deprecated).
$POST
VariabIes provided to the script via HTTP POST. AnaIogous to the oId SHTTPPOSTJARS array
(which is stiII avaiIabIe, but deprecated).
$COOKIE
VariabIes provided to the script via HTTP cookies. AnaIogous to the oId SHTTPCOOKIEJARS
array (which is stiII avaiIabIe, but deprecated).
$FILES
VariabIes provided to the script via HTTP post IiIe upIoads. AnaIogous to the oId
SHTTPPOSTFILES array (which is stiII avaiIabIe, but deprecated). See POST method upIoads Ior
more inIormation.
$ENV
VariabIes provided to the script via the environment. AnaIogous to the oId SHTTPENJJARS array
(which is stiII avaiIabIe, but deprecated).
$REQUEST
VariabIes provided to the script via the GET, POST, and COOKIE input mechanisms, and which
thereIore cannot be trusted. The presence and order oI variabIe incIusion in this array is deIined
according to the PHP variabIesorder conIiguration directive. This array has no direct anaIogue in
versions oI PHP prior to 4.1.0. See aIso importrequestvariabIes().
Caution
Since PHP 4.3.0, FILE inIormation Irom SFILES does not exist in SREQUEST.
Note: When running on the command Iine , this wiII not incIude the argv and argc entries;
these are present in the SSERJER array.
$SESSION
VariabIes which are currentIy registered to a script's session. AnaIogous to the oId
SHTTPSESSIONJARS array (which is stiII avaiIabIe, but deprecated). See the Session handIing
Iunctions section Ior more inIormation.
Variable scope
The scope oI a variabIe is the context within which it is deIined. For the most part aII PHP variabIes onIy have
a singIe scope. This singIe scope spans incIuded and required IiIes as weII. For exampIe:
<?php
$a = 1;
include 'b.inc';
?>
Here the Sa variabIe wiII be avaiIabIe within the incIuded b.inc script. However, within user-deIined Iunctions
a IocaI Iunction scope is introduced. Any variabIe used inside a Iunction is by deIauIt Iimited to the IocaI
Iunction scope. For exampIe:
<?php
$a = 1; /* global scope */
function Test()
{
echo $a; /* reference to local scope variable */
}
Test();
?>
This script wiII not produce any output because the echo statement reIers to a IocaI version oI the Sa variabIe,
and it has not been assigned a vaIue within this scope. You may notice that this is a IittIe bit diIIerent Irom the
C Ianguage in that gIobaI variabIes in C are automaticaIIy avaiIabIe to Iunctions unIess speciIicaIIy overridden
by a IocaI deIinition. This can cause some probIems in that peopIe may inadvertentIy change a gIobaI variabIe.
In PHP gIobaI variabIes must be decIared gIobaI inside a Iunction iI they are going to be used in that Iunction.
The global keyword
First, an exampIe use oI global:
Example 12.2. Using global
<?php
$a = 1;
$b = 2;
function Sum()
{
global $a, $b;
$b = $a + $b;
}
Sum();
echo $b;
?>
The above script wiII output "3". By decIaring Sa and Sb gIobaI within the Iunction, aII reIerences to either
variabIe wiII reIer to the gIobaI version. There is no Iimit to the number oI gIobaI variabIes that can be
manipuIated by a Iunction.
A second way to access variabIes Irom the gIobaI scope is to use the speciaI PHP-deIined SGLOBALS array.
The previous exampIe can be rewritten as:
Example 12.3. Using ()*+,-*. instead of global
<?php
$a = 1;
$b = 2;
function Sum()
{
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}
Sum();
echo $b;
?>
The SGLOBALS array is an associative array with the name oI the gIobaI variabIe being the key and the
contents oI that variabIe being the vaIue oI the array eIement. Notice how SGLOBALS exists in any scope, this
is because $GLOBALS is a supergIobaI. Here's an exampIe demonstrating the power oI supergIobaIs:
Example 12.4. Example demonstrating superglobals and scope
<?php
function test_global()
{
// Most predefined variables aren't "super" and require
// 'global' to be available to the functions local scope.
global $HTTP_POST_VARS;
echo $HTTP_POST_VARS['name'];
// Superglobals are available in any scope and do
// not require 'global'. Superglobals are available
// as of PHP 4.1.0, and HTTP_POST_VARS is now
// deemed deprecated.
echo $_POST['name'];
}
?>
Using static variables
Another important Ieature oI variabIe scoping is the static variabIe. A static variabIe exists onIy in a IocaI
Iunction scope, but it does not Iose its vaIue when program execution Ieaves this scope. Consider the
IoIIowing exampIe:
Example 12.5. Example demonstrating need for static variables
<?php
function Test()
{
$a = 0;
echo $a;
$a++;
}
?>
This Iunction is quite useIess since every time it is caIIed it sets Sa to 0 and prints "0". The Sa which
increments the variabIe serves no purpose since as soon as the Iunction exits the Sa variabIe disappears. To
make a useIuI counting Iunction which wiII not Iose track oI the current count, the Sa variabIe is decIared
static:
Example 12.6. Example use of static variables
<?php
function Test()
{
static $a = 0;
echo $a;
$a++;
}
?>
Now, every time the Test() Iunction is caIIed it wiII print the vaIue oI Sa and increment it.
Static variabIes aIso provide one way to deaI with recursive Iunctions. A recursive Iunction is one which caIIs
itseII. Care must be taken when writing a recursive Iunction because it is possibIe to make it recurse
indeIiniteIy. You must make sure you have an adequate way oI terminating the recursion. The IoIIowing
simpIe Iunction recursiveIy counts to 10, using the static variabIe Scount to know when to stop:
Example 12.7. Static variables with recursive functions
<?php
function Test()
{
static $count = 0;
$count++;
echo $count;
if ($count < 10) {
Test();
}
$count--;
}
?>
Note: Static variabIes may be decIared as seen in the exampIes above. Trying to assign vaIues to these
variabIes which are the resuIt oI expressions wiII cause a parse error.
Example 12.8. Declaring static variables
<?php
function foo(){
static $int = 0; // correct
static $int = 1+2; // wrong (as it is an expression)
static $int = sqrt(121); // wrong (as it is an expression too)
$int++;
echo $int;
}
?>
References with global and static variables
The Zend Engine 1, driving PHP 4, impIements the static and gIobaI modiIier Ior variabIes in terms oI
reIerences. For exampIe, a true gIobaI variabIe imported inside a Iunction scope with the global statement
actuaIIy creates a reIerence to the gIobaI variabIe. This can Iead to unexpected behaviour which the IoIIowing
exampIe addresses:
<?php
function test_global_ref() {
global $obj;
$obj = &new stdclass;
}
function test_global_noref() {
global $obj;
$obj = new stdclass;
}
test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);
?>
Executing this exampIe wiII resuIt in the IoIIowing output:
NULL
object(stdClass)(0) {
}
A simiIar behaviour appIies to the static statement. ReIerences are not stored staticaIIy:
<?php
function &get_instance_ref() {
static $obj;
echo 'Static object: ';
var_dump($obj);
if (!isset($obj)) {
// Assign a reference to the static variable
$obj = &new stdclass;
}
$obj->property++;
return $obj;
}
function &get_instance_noref() {
static $obj;
echo 'Static object: ';
var_dump($obj);
if (!isset($obj)) {
// Assign the object to the static variable
$obj = new stdclass;
}
$obj->property++;
return $obj;
}
$obj1 = get_instance_ref();
$still_obj1 = get_instance_ref();
echo "\n";
$obj2 = get_instance_noref();
$still_obj2 = get_instance_noref();
?>
Executing this exampIe wiII resuIt in the IoIIowing output:
Static object: NULL
Static object: NULL
Static object: NULL
Static object: object(stdClass)(1) {
["property"]=>
int(1)
}
This exampIe demonstrates that when assigning a reIerence to a static variabIe, it's not remembered when you
caII the &getinstanceref() Iunction a second time.
Variable variables
Sometimes it is convenient to be abIe to have variabIe variabIe names. That is, a variabIe name which can be
set and used dynamicaIIy. A normaI variabIe is set with a statement such as:
<?php
$a = 'hello';
?>
A variabIe variabIe takes the vaIue oI a variabIe and treats that as the name oI a variabIe. In the above
exampIe, hello, can be used as the name oI a variabIe by using two doIIar signs. i.e.
<?php
$$a = 'world';
?>
At this point two variabIes have been deIined and stored in the PHP symboI tree: Sa with contents "heIIo" and
Shello with contents "worId". ThereIore, this statement:
<?php
echo "$a ${$a}";
?>
produces the exact same output as:
<?php
echo "$a $hello";
?>
i.e. they both produce: hello world.
In order to use variabIe variabIes with arrays, you have to resoIve an ambiguity probIem. That is, iI you write
SSa[1{ then the parser needs to know iI you meant to use Sa[1{ as a variabIe, or iI you wanted SSa as the
variabIe and then the |1] index Irom that variabIe. The syntax Ior resoIving this ambiguity is: S{Sa[1{} Ior the
Iirst case and S{Sa}[1{ Ior the second.
Warning
PIease note that variabIe variabIes cannot be used with PHP's SupergIobaI arrays within Iunctions or cIass
methods. The variabIe Sthis is aIso a speciaI variabIe that cannot be reIerenced dynamicaIIy.
Variables from outside PHP
HTML Forms (GET and POST)
When a Iorm is submitted to a PHP script, the inIormation Irom that Iorm is automaticaIIy made avaiIabIe to
the script. There are many ways to access this inIormation, Ior exampIe:
Example 12.9. A simple HTML form
<form action="foo.php" method="post">
Name: <input type="text" name="username" /><br />
Email: <input type="text" name="email" /><br />
<input type="submit" name="submit" value="Submit me!" />
</form>
Depending on your particuIar setup and personaI preIerences, there are many ways to access data Irom your
HTML Iorms. Some exampIes are:
Example 12.10. Accessing data from a simple POST HTMLform
<?php
// Available since PHP 4.1.0
echo $_POST['username'];
echo $_REQUEST['username'];
import_request_variables('p', 'p_');
echo $p_username;
// Available since PHP 3. As of PHP 5.0.0, these long predefined
// variables can be disabled with the register_long_arrays directive.
echo $HTTP_POST_VARS['username'];
// Available if the PHP directive register_globals = on. As of
// PHP 4.2.0 the default value of register_globals = off.
// Using/relying on this method is not preferred.
echo $username;
?>
Using a GET Iorm is simiIar except you'II use the appropriate GET predeIined variabIe instead. GET aIso
appIies to the QUERYSTRING (the inIormation aIter the '?' in a URL). So, Ior exampIe,
http.www.example.comtest.php?id3 contains GET data which is accessibIe with SGET[id{. See aIso
$REQUEST and importrequestvariabIes().
Note: SupergIobaI arrays, Iike SPOST and SGET, became avaiIabIe in PHP 4.1.0
As shown, beIore PHP 4.2.0 the deIauIt vaIue Ior registergIobaIs was on. And, in PHP 3 it was aIways on.
The PHP community is encouraging aII to not reIy on this directive as it's preIerred to assume it's off and code
accordingIy.
Note: The magicquotesgpc conIiguration directive aIIects Get, Post and Cookie vaIues. II turned on, vaIue
(It's "PHP!") wiII automagicaIIy become (It\'s \"PHP!\"). Escaping is needed Ior DB insertion. See aIso
addsIashes(), stripsIashes() and magicquotessybase.
PHP aIso understands arrays in the context oI Iorm variabIes (see the reIated Iaq). You may, Ior exampIe,
group reIated variabIes together, or use this Ieature to retrieve vaIues Irom a muItipIe seIect input. For
exampIe, Iet's post a Iorm to itseII and upon submission dispIay the data:
Example 12.11. More complex form variables
<?php
if ($_POST) {
echo '<pre>';
echo htmlspecialchars(print_r($_POST, true));
echo '</pre>';
}
?>
<form action="" method="post">
Name: <input type="text" name="personal[name]" /><br />
Email: <input type="text" name="personal[email]" /><br />
Beer: <br />
<select multiple name="beer[]">
<option value="warthog">Warthog</option>
<option value="guinness">Guinness</option>
<option value="stuttgarter">Stuttgarter Schwabenbru</option>
</select><br />
<input type="submit" value="submit me!" />
</form>
In PHP 3, the array Iorm variabIe usage is Iimited to singIe-dimensionaI arrays. As oI PHP 4, no such
restriction appIies.
IMAGE SUBMIT variabIe names
When submitting a Iorm, it is possibIe to use an image instead oI the standard submit button with a tag Iike:
<input type="image" src="image.gif" name="sub" />
When the user cIicks somewhere on the image, the accompanying Iorm wiII be transmitted to the server with
two additionaI variabIes, subx and suby. These contain the coordinates oI the user cIick within the image.
The experienced may note that the actuaI variabIe names sent by the browser contains a period rather than an
underscore, but PHP converts the period to an underscore automaticaIIy.
HTTP Cookies
PHP transparentIy supports HTTP cookies as deIined by Netscape's Spec. Cookies are a mechanism Ior
storing data in the remote browser and thus tracking or identiIying return users. You can set cookies using the
setcookie() Iunction. Cookies are part oI the HTTP header, so the SetCookie Iunction must be caIIed beIore
any output is sent to the browser. This is the same restriction as Ior the header() Iunction. Cookie data is then
avaiIabIe in the appropriate cookie data arrays, such as SCOOKIE, SHTTPCOOKIEJARS as weII as in
SREQUEST. See the setcookie() manuaI page Ior more detaiIs and exampIes.
II you wish to assign muItipIe vaIues to a singIe cookie variabIe, you may assign it as an array. For exampIe:
<?php
setcookie("MyCookie[foo]", 'Testing 1', time()+3600);
setcookie("MyCookie[bar]", 'Testing 2', time()+3600);
?>
That wiII create two separate cookies aIthough MyCookie wiII now be a singIe array in your script. II you
want to set just one cookie with muItipIe vaIues, consider using seriaIize() or expIode() on the vaIue Iirst.
Note that a cookie wiII repIace a previous cookie by the same name in your browser unIess the path or domain
is diIIerent. So, Ior a shopping cart appIication you may want to keep a counter and pass this aIong. i.e.
Example 12.12. A setcookie() example
<?php
if (isset($_COOKIE['count'])) {
$count = $_COOKIE['count'] + 1;
} else {
$count = 1;
}
setcookie('count', $count, time()+3600);
setcookie("Cart[$count]", $item, time()+3600);
?>
Dots in incoming variable names
TypicaIIy, PHP does not aIter the names oI variabIes when they are passed into a script. However, it shouId be
noted that the dot (period, IuII stop) is not a vaIid character in a PHP variabIe name. For the reason, Iook at it:
<?php
$varname.ext; /* invalid variable name */
?> Now, what the parser sees is a variabIe named Svarname, IoIIowed by the string concatenation operator,
IoIIowed by the barestring (i.e. unquoted string which doesn't match any known key or reserved words) 'ext'.
ObviousIy, this doesn't have the intended resuIt.
For this reason, it is important to note that PHP wiII automaticaIIy repIace any dots in incoming variabIe
names with underscores.
Determining variable types
Because PHP determines the types oI variabIes and converts them (generaIIy) as needed, it is not aIways
obvious what type a given variabIe is at any one time. PHP incIudes severaI Iunctions which Iind out what
type a variabIe is, such as: gettype(), isarray(), isIIoat(), isint(), isobject(), and isstring(). See aIso the
chapter on Types.
Chapter 13. Constants
Syntax
You can deIine a constant by using the deIine()-Iunction. Once a constant is deIined, it can never be changed
or undeIined.
OnIy scaIar data (booIean, integer, IIoat and string) can be contained in constants. Do not deIine resource
constants.
You can get the vaIue oI a constant by simpIy speciIying its name. UnIike with variabIes, you shouId not
prepend a constant with a S. You can aIso use the Iunction constant() to read a constant's vaIue iI you wish to
obtain the constant's name dynamicaIIy. Use getdeIinedconstants() to get a Iist oI aII deIined constants.
Note: Constants and (gIobaI) variabIes are in a diIIerent namespace. This impIies that Ior exampIe TRUE and
STRUE are generaIIy diIIerent.
II you use an undeIined constant, PHP assumes that you mean the name oI the constant itseII, just as iI you
caIIed it as a string (CONSTANT vs "CONSTANT"). An error oI IeveI ENOTICE wiII be issued when this
happens. See aIso the manuaI entry on why $Ioo|bar] is wrong (unIess you Iirst deIine() bar as a constant). II
you simpIy want to check iI a constant is set, use the deIined() Iunction.
These are the diIIerences between constants and variabIes:
Constants do not have a doIIar sign (S) beIore them;
Constants may onIy be deIined using the deIine() Iunction, not by simpIe assignment;
Constants may be deIined and accessed anywhere without regard to variabIe scoping ruIes;
Constants may not be redeIined or undeIined once they have been set; and
Constants may onIy evaIuate to scaIar vaIues.
Example 13.2. Defining Constants
<?php
define("CONSTANT", "Hello world.");
echo CONSTANT; // outputs "Hello world."
echo Constant; // outputs "Constant" and issues a notice.
?>
See aIso CIass Constants.
Magic constants
PHP provides a Iarge number oI predeIined constants to any script which it runs. Many oI these constants,
however, are created by various extensions, and wiII onIy be present when those extensions are avaiIabIe,
either via dynamic Ioading or because they have been compiIed in.
There are Iive magicaI constants that change depending on where they are used. For exampIe, the vaIue oI
__LINE__ depends on the Iine that it's used on in your script. These speciaI constants are case-insensitive and
are as IoIIows:
Table 13.1. A few "magical" PHP constants
Name Description
__LINE__
The current Iine number oI the IiIe.
Name Description
__FILE__
The IuII path and IiIename oI the IiIe. II used inside an incIude, the name oI the incIuded IiIe is
returned. Since PHP 4.0.2, __FILE__ aIways contains an absoIute path whereas in oIder
versions it contained reIative path under some circumstances.
__FUNCTION__
The Iunction name. (Added in PHP 4.3.0) As oI PHP 5 this constant returns the Iunction name
as it was decIared (case-sensitive). In PHP 4 its vaIue is aIways Iowercased.
__CLASS__
The cIass name. (Added in PHP 4.3.0) As oI PHP 5 this constant returns the cIass name as it
was decIared (case-sensitive). In PHP 4 its vaIue is aIways Iowercased.
__METHOD__
The cIass method name. (Added in PHP 5.0.0) The method name is returned as it was decIared
(case-sensitive).
Chapter 14. Expressions
Expressions are the most important buiIding stones oI PHP. In PHP, aImost anything you write is an
expression. The simpIest yet most accurate way to deIine an expression is "anything that has a vaIue".
The most basic Iorms oI expressions are constants and variabIes. When you type "$a 5", you're assigning '5'
into $a. '5', obviousIy, has the vaIue 5, or in other words '5' is an expression with the vaIue oI 5 (in this case, '5'
is an integer constant).
AIter this assignment, you'd expect $a's vaIue to be 5 as weII, so iI you wrote $b $a, you'd expect it to
behave just as iI you wrote $b 5. In other words, $a is an expression with the vaIue oI 5 as weII. II
everything works right, this is exactIy what wiII happen.
SIightIy more compIex exampIes Ior expressions are Iunctions. For instance, consider the IoIIowing Iunction:
<?php
function foo ()
{
return 5;
}
?>
Assuming you're IamiIiar with the concept oI Iunctions (iI you're not, take a Iook at the chapter about
Iunctions), you'd assume that typing Sc foo() is essentiaIIy just Iike writing Sc 5, and you're right.
Functions are expressions with the vaIue oI their return vaIue. Since Ioo() returns 5, the vaIue oI the
expression 'Ioo()' is 5. UsuaIIy Iunctions don't just return a static vaIue but compute something.
OI course, vaIues in PHP don't have to be integers, and very oIten they aren't. PHP supports Iour scaIar vaIue
types: integer vaIues, IIoating point vaIues (IIoat), string vaIues and booIean vaIues (scaIar vaIues are vaIues
that you can't 'break' into smaIIer pieces, unIike arrays, Ior instance). PHP aIso supports two composite (non-
scaIar) types: arrays and objects. Each oI these vaIue types can be assigned into variabIes or returned Irom
Iunctions.
PHP takes expressions much Iurther, in the same way many other Ianguages do. PHP is an expression-oriented
Ianguage, in the sense that aImost everything is an expression. Consider the exampIe we've aIready deaIt with,
'$a 5'. It's easy to see that there are two vaIues invoIved here, the vaIue oI the integer constant '5', and the
vaIue oI $a which is being updated to 5 as weII. But the truth is that there's one additionaI vaIue invoIved here,
and that's the vaIue oI the assignment itseII. The assignment itseII evaIuates to the assigned vaIue, in this case
5. In practice, it means that '$a 5', regardIess oI what it does, is an expression with the vaIue 5. Thus, writing
something Iike '$b ($a 5)' is Iike writing '$a 5; $b 5;' (a semicoIon marks the end oI a statement). Since
assignments are parsed in a right to IeIt order, you can aIso write '$b $a 5'.
Another good exampIe oI expression orientation is pre- and post-increment and decrement. Users oI PHP and
many other Ianguages may be IamiIiar with the notation oI variabIe and variabIe--. These are increment and
decrement operators. In PHP/FI 2, the statement '$a' has no vaIue (is not an expression), and thus you can't
assign it or use it in any way. PHP enhances the increment/decrement capabiIities by making these expressions
as weII, Iike in C. In PHP, Iike in C, there are two types oI increment - pre-increment and post-increment. Both
pre-increment and post-increment essentiaIIy increment the variabIe, and the eIIect on the variabIe is identicaI.
The diIIerence is with the vaIue oI the increment expression. Pre-increment, which is written '$variabIe',
evaIuates to the incremented vaIue (PHP increments the variabIe beIore reading its vaIue, thus the name 'pre-
increment'). Post-increment, which is written '$variabIe' evaIuates to the originaI vaIue oI $variabIe, beIore
it was incremented (PHP increments the variabIe aIter reading its vaIue, thus the name 'post-increment').
A very common type oI expressions are comparison expressions. These expressions evaIuate to either FALSE
or TRUE. PHP supports > (bigger than), > (bigger than or equaI to), (equaI), ! (not equaI), (smaIIer
than) and (smaIIer than or equaI to). The Ianguage aIso supports a set oI strict equivaIence operators:
(equaI to and same type) and ! (not equaI to or not same type). These expressions are most commonIy used
inside conditionaI execution, such as if statements.
The Iast exampIe oI expressions we'II deaI with here is combined operator-assignment expressions. You
aIready know that iI you want to increment $a by 1, you can simpIy write '$a' or '$a'. But what iI you
want to add more than one to it, Ior instance 3? You couId write '$a' muItipIe times, but this is obviousIy
not a very eIIicient or comIortabIe way. A much more common practice is to write '$a $a 3'. '$a 3'
evaIuates to the vaIue oI $a pIus 3, and is assigned back into $a, which resuIts in incrementing $a by 3. In
PHP, as in severaI other Ianguages Iike C, you can write this in a shorter way, which with time wouId become
cIearer and quicker to understand as weII. Adding 3 to the current vaIue oI $a can be written '$a 3'. This
means exactIy "take the vaIue oI $a, add 3 to it, and assign it back into $a". In addition to being shorter and
cIearer, this aIso resuIts in Iaster execution. The vaIue oI '$a 3', Iike the vaIue oI a reguIar assignment, is
the assigned vaIue. Notice that it is NOT 3, but the combined vaIue oI $a pIus 3 (this is the vaIue that's
assigned into $a). Any two-pIace operator can be used in this operator-assignment mode, Ior exampIe '$a - 5'
(subtract 5 Irom the vaIue oI $a), '$b * 7' (muItipIy the vaIue oI $b by 7), etc.
There is one more expression that may seem odd iI you haven't seen it in other Ianguages, the ternary
conditionaI operator:
<?php
$first ? $second : $third
?>
II the vaIue oI the Iirst subexpression is TRUE (non-zero), then the second subexpression is evaIuated, and that
is the resuIt oI the conditionaI expression. Otherwise, the third subexpression is evaIuated, and that is the
vaIue.
The IoIIowing exampIe shouId heIp you understand pre- and post-increment and expressions in generaI a bit
better:
<?php
function double($i)
{
return $i*2;
}
$b = $a = 5; /* assign the value five into the variable $a and $b */
$c = $a++; /* post-increment, assign original value of $a
(5) to $c */
$e = $d = ++$b; /* pre-increment, assign the incremented value of
$b (6) to $d and $e */
/* at this point, both $d and $e are equal to 6 */
$f = double($d++); /* assign twice the value of $d before
the increment, 2*6 = 12 to $f */
$g = double(++$e); /* assign twice the value of $e after
the increment, 2*7 = 14 to $g */
$h = $g += 10; /* first, $g is incremented by 10 and ends with the
value of 24. the value of the assignment (24) is
then assigned into $h, and $h ends with the value
of 24 as well. */
?>
Some expressions can be considered as statements. In this case, a statement has the Iorm oI 'expr' ';' that is, an
expression IoIIowed by a semicoIon. In '$b$a5;', $a5 is a vaIid expression, but it's not a statement by
itseII. '$b$a5;' however is a vaIid statement.
One Iast thing worth mentioning is the truth vaIue oI expressions. In many events, mainIy in conditionaI
execution and Ioops, you're not interested in the speciIic vaIue oI the expression, but onIy care about whether
it means TRUE or FALSE. The constants TRUE and FALSE (case-insensitive) are the two possibIe booIean vaIues.
When necessary, an expression is automaticaIIy converted to booIean. See the section about type-casting Ior
detaiIs about how.
PHP provides a IuII and powerIuI impIementation oI expressions, and documenting it entireIy goes beyond the
scope oI this manuaI. The above exampIes shouId give you a good idea about what expressions are and how
you can construct useIuI expressions. Throughout the rest oI this manuaI we'II write expr to indicate any vaIid
PHP expression.
Chapter 15. Operators
An operator is something that you Ieed with one or more vaIues (or expressions, in programming jargon)
which yieIds another vaIue (so that the construction itseII becomes an expression). So you can think oI
Iunctions or constructions that return a vaIue (Iike print) as operators and those that return nothing (Iike echo)
as any other thing.
There are three types oI operators. FirstIy there is the unary operator which operates on onIy one vaIue, Ior
exampIe ! (the negation operator) or (the increment operator). The second group are termed binary
operators; this group contains most oI the operators that PHP supports, and a Iist IoIIows beIow in the section
Operator Precedence.
The third group is the ternary operator: ?:. It shouId be used to seIect between two expressions depending on a
third one, rather than to seIect two sentences or paths oI execution. Surrounding ternary expressions with
parentheses is a very good idea.
Operator Precedence
The precedence oI an operator speciIies how "tightIy" it binds two expressions together. For exampIe, in the
expression 1 5 * 3, the answer is 16 and not 18 because the muItipIication ("*") operator has a higher
precedence than the addition ("") operator. Parentheses may be used to Iorce precedence, iI necessary. For
instance: (1 5) * 3 evaIuates to 18. II operator precedence is equaI, IeIt to right associativity is used.
The IoIIowing tabIe Iists the precedence oI operators with the highest-precedence operators Iisted at the top oI
the tabIe. Operators on the same Iine have equaI precedence, in which case their associativity decides which
order to evaIuate them in.
Table 15.1. Operator Precedence
Associativity Operators Additional Information
non-associative new new
IeIt | array()
non-associative -- increment/decrement
non-associative ~ - (int) (IIoat) (string) (array) (object) types
non-associative instanceoI types
right ! IogicaI
IeIt * / % arithmetic
IeIt - . arithmetic and string
IeIt >> bitwise
non-associative > > comparison
non-associative ! ! comparison
IeIt & bitwise and reIerences
IeIt bitwise
IeIt bitwise
IeIt && IogicaI
IeIt IogicaI
IeIt ? : ternary
right - * / . % & >> assignment
IeIt and IogicaI
IeIt xor IogicaI
IeIt or IogicaI
IeIt , many uses
LeIt associativity means that the expression is evaIuated Irom IeIt to right, right associativity means the
opposite.
Example 15.1. Associativity
<?php
$a = 3 * 3 % 5; // (3 * 3) % 5 = 4
$a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2
$a = 1;
$b = 2;
$a = $b += 3; // $a = ($b += 3) -> $a = 5, $b = 5
?>
Use parentheses to increase readabiIity oI the code.
Note: AIthough has a Iower precedence than most other operators, PHP wiII stiII aIIow expressions simiIar
to the IoIIowing: if (!Sa foo()), in which case the return vaIue oI foo() is put into Sa.
Arithmetic Operators
Remember basic arithmetic Irom schooI? These work just Iike those.
Table 15.2. Arithmetic Operators
Example Name Result
-$a Negation Opposite oI $a.
$a $b Addition Sum oI $a and $b.
$a - $b Subtraction DiIIerence oI $a and $b.
$a * $b MuItipIication Product oI $a and $b.
$a / $b Division Quotient oI $a and $b.
$a % $b ModuIus Remainder oI $a divided by $b.
The division operator ("/") returns a IIoat vaIue unIess the two operands are integers (or strings that get
converted to integers) and the numbers are evenIy divisibIe, in which case an integer vaIue wiII be returned.
Operands oI moduIus are converted to integers (by stripping the decimaI part) beIore processing.
Note: Remainder Sa Sb is negative Ior negative Sa.
Assignment Operators
The basic assignment operator is "". Your Iirst incIination might be to think oI this as "equaI to". Don't. It
reaIIy means that the IeIt operand gets set to the vaIue oI the expression on the rights (that is, "gets set to").
The vaIue oI an assignment expression is the vaIue assigned. That is, the vaIue oI "$a 3" is 3. This aIIows
you to do some tricky things:
<?php
$a = ($b = 4) + 5; // $a is equal to 9 now, and $b has been set to 4.
?>
In addition to the basic assignment operator, there are "combined operators" Ior aII oI the binary arithmetic,
array union and string operators that aIIow you to use a vaIue in an expression and then set its vaIue to the
resuIt oI that expression. For exampIe:
<?php
$a = 3;
$a += 5; // sets $a to 8, as if we had said: $a = $a + 5;
$b = "Hello ";
$b .= "There!"; // sets $b to "Hello There!", just like $b = $b . "There!";
?>
Note that the assignment copies the originaI variabIe to the new one (assignment by vaIue), so changes to one
wiII not aIIect the other. This may aIso have reIevance iI you need to copy something Iike a Iarge array inside
a tight Ioop. Since PHP 4, assignment by reIerence has been supported, using the $var = &$othervar;
syntax, but this is not possibIe in PHP 3. 'Assignment by reIerence' means that both variabIes end up pointing
at the same data, and nothing is copied anywhere. To Iearn more about reIerences, pIease read ReIerences
expIained. As oI PHP 5, objects are assigned by reIerence unIess expIicitIy toId otherwise with the new cIone
keyword.
Bitwise Operators
Bitwise operators aIIow you to turn speciIic bits within an integer on or oII. II both the IeIt- and right-hand
parameters are strings, the bitwise operator wiII operate on the characters' ASCII vaIues.
<?php
echo 12 ^ 9; // Outputs '5'
echo "12" ^ "9"; // Outputs the Backspace character (ascii 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello"; // Outputs the ascii values #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4
?>
Table 15.3. Bitwise Operators
Example Name Result
$a & $b And Bits that are set in both $a and $b are set.
$a $b Or Bits that are set in either $a or $b are set.
$a $b Xor Bits that are set in $a or $b but not both are set.
~ $a Not Bits that are set in $a are not set, and vice versa.
$a $b ShiIt IeIt ShiIt the bits oI $a $b steps to the IeIt (each step means "muItipIy by two")
$a >> $b ShiIt right ShiIt the bits oI $a $b steps to the right (each step means "divide by two")
Warning
Don't right shiIt Ior more than 32 bits on 32 bits systems. Don't IeIt shiIt in case it resuIts to number Ionger
than 32 bits.
Comparison Operators
Comparison operators, as their name impIies, aIIow you to compare two vaIues. You may aIso be interested in
viewing the type comparison tabIes, as they show exampIes oI various type reIated comparisons.
Table 15.4. Comparison Operators
Exampl
e
Name Result
$a ==
$b
Equal TRUE if $a is equal to $b.
$a ===
$b
dentical
TRUE if $a is equal to $b, and they are of the same type.
(introduced in PHP 4)
$a != $b Not equal TRUE if $a is not equal to $b.
$a <>
$b
Not equal TRUE if $a is not equal to $b.
$a !==
$b
Not identical
TRUE if $a is not equal to $b, or they are not of the same type.
(introduced in PHP 4)
$a < $b Less than TRUE if $a is strictly less than $b.
$a > $b Greater than TRUE if $a is strictly greater than $b.
$a <=
$b
Less than or equal
to
TRUE if $a is less than or equal to $b.
$a >=
$b
Greater than or
equal to
TRUE if $a is greater than or equal to $b.
II you compare an integer with a string, the string is converted to a number. II you compare two numericaI
strings, they are compared as integers. These ruIes aIso appIy to the switch statement.
<?php
var_dump(0 == "a"); // 0 == 0 -> true
var_dump("1" == "01"); // 1 == 1 -> true
var_dump("1" == "1e0"); // 1 == 1 -> true
switch ("a") {
case 0:
echo "0";
break;
case "a": // never reached because "a" is already matched with 0
echo "a";
break;
}
?>
For various types, comparison is done according to the IoIIowing tabIe (in order).
Table 15.5. Comparison with Various Types
Type of
Operand 1
Type of
Operand 2
Result
null or string string Convert NULL to "", numerical or lexical comparison
bool or null anything Convert to bool, FALSE < TRUE
ob|ect ob|ect
Built-in classes can define its own comparison, different
classes are uncomparable, same class - compare properties
the same way as arrays (PHP 4), PHP 5 has its own
explanation
Type of
Operand 1
Type of
Operand 2
Result
string,
resource or
number
string,
resource or
number
Translate strings and resources to numbers, usual math
array array
Array with fewer members is smaller, if key from operand 1 is
not found in operand 2 then arrays are uncomparable,
otherwise - compare value by value (see following example)
array anything array is always greater
ob|ect anything ob|ect is always greater
Example 15.2. Transcription of standard array comparison
<?php
// Arrays are compared like this with standard comparison operators
function standard_array_compare($op1, $op2)
{
if (count($op1) < count($op2)) {
return -1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return 1; // $op1 > $op2
}
foreach ($op1 as $key => $val) {
if (!array_key_exists($key, $op2)) {
return null; // uncomparable
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
?>
See aIso strcasecmp(), strcmp(), Array operators, and the manuaI section on Types.
Ternary Operator
Another conditionaI operator is the "?:" (or ternary) operator.
Example 15.3. Assigning a default value
<?php
// Example usage for: Ternary Operator
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
// The above is identical to this if/else statement
if (empty($_POST['action'])) {
$action = 'default';
} else {
$action = $_POST['action'];
}
?>
The expression (exprJ) ? (expr2) : (expr3) evaluates to expr2 if expr1 evaluates to TRUE,
and expr3 if expr1 evaluates to FALSE.
Note: PIease note that the ternary operator is a statement, and that it doesn't evaIuate to a variabIe, but to the
resuIt oI a statement. This is important to know iI you want to return a variabIe by reIerence. The statement
return Svar 42 ? Sa . Sb, in a return-by-reIerence Iunction wiII thereIore not work and a warning is issued
in Iater PHP versions.
Note: Is is recommended that you avoid "stacking" ternary expressions. PHP's behaviour when using more
than one ternary operator within a singIe statement is non-obvious:
Example 15.4. Non-obvious Ternary Behaviour
<?php
// on first glance, the following appears to output 'true'
echo (true?'true':false?'t':'f');
// however, the actual output of the above is 't'
// this is because ternary expressions are evaluated from left to right
// the following is a more obvious version of the same code as above
echo ((true ? 'true' : 'false') ? 't' : 'f');
// here, you can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool)true, thus returning the true branch of the
// second ternary expression.
?>
Error Control Operators
PHP supports one error controI operator: the at sign (). When prepended to an expression in PHP, any error
messages that might be generated by that expression wiII be ignored.
II the trackerrors Ieature is enabIed, any error message generated by the expression wiII be saved in the
variabIe $phperrormsg. This variabIe wiII be overwritten on each error, so check earIy iI you want to use it.
<?php
/* Intentional file error */
$my_file = @file ('non_existent_file') or
die ("Failed opening file: error was '$php_errormsg'");
// this works for any expression, not just functions:
$value = @$cache[$key];
// will not issue a notice if the index $key doesn't exist.
?>
Note: The -operator works onIy on expressions. A simpIe ruIe oI thumb is: iI you can take the vaIue oI
something, you can prepend the operator to it. For instance, you can prepend it to variabIes, Iunction and
incIude() caIIs, constants, and so Iorth. You cannot prepend it to Iunction or cIass deIinitions, or conditionaI
structures such as if and foreach, and so Iorth.
See aIso errorreporting() and the manuaI section Ior Error HandIing and Logging Iunctions.
Warning
CurrentIy the "" error-controI operator preIix wiII even disabIe error reporting Ior criticaI errors that wiII
terminate script execution. Among other things, this means that iI you use "" to suppress errors Irom a
certain Iunction and either it isn't avaiIabIe or has been mistyped, the script wiII die right there with no
indication as to why.
Execution Operators
PHP supports one execution operator: backticks (``). Note that these are not singIe-quotes! PHP wiII attempt
to execute the contents oI the backticks as a sheII command; the output wiII be returned (i.e., it won't simpIy
be dumped to output; it can be assigned to a variabIe). Use oI the backtick operator is identicaI to sheIIexec().
<?php
$output = ls -al;
echo "<pre>$output</pre>";
?>
Note: The backtick operator is disabIed when saIe mode is enabIed or sheIIexec() is disabIed.
Incrementing/Decrementing Operators
PHP supports C-styIe pre- and post-increment and decrement operators.
Note: The increment/decrement operators do not aIIect booIean vaIues. Decrementing NULL vaIues has no
eIIect too, but incrementing them resuIts in 1.
Table 15.6. Increment/decrement Operators
Example Name Effect
$a Pre-increment Increments $a by one, then returns $a.
$a Post-increment Returns $a, then increments $a by one.
--$a Pre-decrement Decrements $a by one, then returns $a.
$a-- Post-decrement Returns $a, then decrements $a by one.
Here's a simpIe exampIe script:
<?php
echo "<h3>Postincrement</h3>";
$a = 5;
echo "Should be 5: " . $a++ . "<br />\n";
echo "Should be 6: " . $a . "<br />\n";
echo "<h3>Preincrement</h3>";
$a = 5;
echo "Should be 6: " . ++$a . "<br />\n";
echo "Should be 6: " . $a . "<br />\n";
echo "<h3>Postdecrement</h3>";
$a = 5;
echo "Should be 5: " . $a-- . "<br />\n";
echo "Should be 4: " . $a . "<br />\n";
echo "<h3>Predecrement</h3>";
$a = 5;
echo "Should be 4: " . --$a . "<br />\n";
echo "Should be 4: " . $a . "<br />\n";
?>
PHP IoIIows PerI's convention when deaIing with arithmetic operations on character variabIes and not C's. For
exampIe, in PerI 'Z'1 turns into 'AA', whiIe in C 'Z'1 turns into '|' ( ord('Z') 90, ord('|') 91 ). Note that
character variabIes can be incremented but not decremented and even so onIy pIain ASCII characters (a-z and
A-Z) are supported.
Example 15.5. Arithmetic Operations on Character Variables
<?php
$i = 'W';
for ($n=0; $n<6; $n++) {
echo ++$i . "\n";
}
?>
The above exampIe wiII output:
X
Y
Z
AA
AB
AC
Incrementing or decrementing booIeans has no eIIect.
Logical Operators
Table 15.7. Logical Operators
Example Name Result
$a and $b And TRUE iI both $a and $b are TRUE.
$a or $b Or TRUE iI either $a or $b is TRUE.
$a xor $b Xor TRUE iI either $a or $b is TRUE, but not both.
! $a Not TRUE iI $a is not TRUE.
$a && $b And TRUE iI both $a and $b are TRUE.
$a $b Or TRUE iI either $a or $b is TRUE.
The reason Ior the two diIIerent variations oI "and" and "or" operators is that they operate at diIIerent
precedences. (See Operator Precedence.)
Example 15.6. Logical operators illustrated
<?php
// foo() will never get called as those operators are short-circuit
$a = (false && foo());
$b = (true || foo());
$c = (false and foo());
$d = (true or foo());
// "||" has a greater precedence than "or"
$e = false || true; // $e will be assigned to (false || true) which is true
$f = false or true; // $f will be assigned to false
var_dump($e, $f);
// "&&" has a greater precedence than "and"
$g = true && false; // $g will be assigned to (true && false) which is false
$h = true and false; // $h will be assigned to true
var_dump($g, $h);
?>
The above exampIe wiII output something simiIar to:
bool(true)
bool(false)
bool(false)
bool(true)
String Operators
There are two string operators. The Iirst is the concatenation operator ('.'), which returns the concatenation oI
its right and IeIt arguments. The second is the concatenating assignment operator ('.'), which appends the
argument on the right side to the argument on the IeIt side. PIease read Assignment Operators Ior more
inIormation.
<?php
$a = "Hello ";
$b = $a . "World!"; // now $b contains "Hello World!"
$a = "Hello ";
$a .= "World!"; // now $a contains "Hello World!"
?>
Array Operators
Table 15.8. Array Operators
Example Name Result
$a $b Union Union oI $a and $b.
$a $b EquaIity TRUE iI $a and $b have the same key/vaIue pairs.
Example Name Result
$a $b Identity
TRUE iI $a and $b have the same key/vaIue pairs in the same order and oI the same
types.
$a ! $b InequaIity TRUE iI $a is not equaI to $b.
$a > $b InequaIity TRUE iI $a is not equaI to $b.
$a ! $b Non-identity TRUE iI $a is not identicaI to $b.
The operator appends eIements oI remaining keys Irom the right handed array to the IeIt handed, whereas
dupIicated keys are NOT overwritten.
<?php
$a = array("a" => "apple", "b" => "banana");
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");
$c = $a + $b; // Union of $a and $b
echo "Union of \$a and \$b: \n";
var_dump($c);
$c = $b + $a; // Union of $b and $a
echo "Union of \$b and \$a: \n";
var_dump($c);
?>
When executed, this script wiII print the IoIIowing: Union of $a and $b:
array(3) {
["a"]=>
string(5) "apple"
["b"]=>
string(6) "banana"
["c"]=>
string(6) "cherry"
}
Union of $b and $a:
array(3) {
["a"]=>
string(4) "pear"
["b"]=>
string(10) "strawberry"
["c"]=>
string(6) "cherry"
}
EIements oI arrays are equaI Ior the comparison iI they have the same key and vaIue.
Example 15.7. Comparing arrays
<?php
$a = array("apple", "banana");
$b = array(1 => "banana", "0" => "apple");
var_dump($a == $b); // bool(true)
var_dump($a === $b); // bool(false)
?>
Type Operators
instanceof is used to determine whether a PHP variabIe is an instantiated object oI a certain cIass:
Example 15.8. Using instanceof with classes
<?php
class MyClass
{
}
class NotMyClass
{
}
$a = new MyClass;
var_dump($a instanceof MyClass);
var_dump($a instanceof NotMyClass);
?>
The above exampIe wiII output:
bool(true)
bool(false)
instanceof can aIso be used to determine whether a variabIe is an instantiated object oI a cIass that inherits
Irom a parent cIass:
Example 15.9. Using instanceof with inherited classes
<?php
class ParentClass
{
}
class MyClass extends ParentClass
{
}
$a = new MyClass;
var_dump($a instanceof MyClass);
var_dump($a instanceof ParentClass);
?>
The above exampIe wiII output:
bool(true)
bool(true)
LastIy, instanceof can aIso be used to determine whether a variabIe is an instantiated object oI a cIass that
impIements an interIace:
Example 15.10. Using instanceof for class
<?php
interface MyInterface
{
}
class MyClass implements MyInterface
{
}
$a = new MyClass;
var_dump($a instanceof MyClass);
var_dump($a instanceof MyInterface);
?>
The above exampIe wiII output:
bool(true)
bool(true)
AIthough instanceof is usuaIIy used with a IiteraI cIassname, it can aIso be used with another object or a string
variabIe:
Example 15.11. Using instanceof with other variables
<?php
interface MyInterface
{
}
class MyClass implements MyInterface
{
}
$a = new MyClass;
$b = new MyClass;
$c = 'MyClass';
$d = 'NotMyClass';
var_dump($a instanceof $b); // $b is an object of class MyClass
var_dump($a instanceof $c); // $c is a string 'MyClass'
var_dump($a instanceof $d); // $d is a string 'NotMyClass'
?>
The above exampIe wiII output:
bool(true)
bool(true)
bool(false)
There are a Iew pitIaIIs to be aware oI. BeIore PHP version 5.1.0, instanceof wouId caII autoIoad() iI the
cIass name did not exist. In addition, iI the cIass was not Ioaded, a IataI error wouId occur. This can be worked
around by using a dvnamic class reference, or a string variabIe containing the cIass name:
Example 15.12. Avoiding classname lookups and fatal errors with instanceof in PHP 5.0
<?php
$d = 'NotMyClass';
var_dump($a instanceof $d); // no fatal error here
?>
The above exampIe wiII output:
bool(false)
The instanceof operator was introduced in PHP 5. BeIore this time isa() was used but isa() has since been
deprecated in Iavor oI instanceof.
Chapter 16. Control Structures
Introduction
Any PHP script is buiIt out oI a series oI statements. A statement can be an assignment, a Iunction caII, a Ioop,
a conditionaI statement or even a statement that does nothing (an empty statement). Statements usuaIIy end
with a semicoIon. In addition, statements can be grouped into a statement-group by encapsuIating a group oI
statements with curIy braces. A statement-group is a statement by itseII as weII. The various statement types
are described in this chapter.
#$/#
OIten you'd want to execute a statement iI a certain condition is met, and a diIIerent statement iI the condition
is not met. This is what else is Ior. else extends an if statement to execute a statement in case the expression in
the if statement evaIuates to FALSE. For exampIe, the IoIIowing code wouId dispIay a is bigger than b iI
Sa is bigger than Sb, and a is NOT bigger than b otherwise:
<?php
if ($a > $b) {
echo "a is bigger than b";
} else {
echo "a is NOT bigger than b";
}
?>
The else statement is onIy executed iI the if expression evaIuated to FALSE, and iI there were any elseif
expressions - onIy iI they evaIuated to FALSE as weII (see eIseiI).
#$/#01
elseif, as its name suggests, is a combination oI if and else. Like else, it extends an if statement to execute a
diIIerent statement in case the originaI if expression evaIuates to FALSE. However, unIike else, it wiII execute
that aIternative expression onIy iI the elseif conditionaI expression evaIuates to TRUE. For exampIe, the
IoIIowing code wouId dispIay a is bigger than b, a equal to b or a is smaller than b:
<?php
if ($a > $b) {
echo "a is bigger than b";
} elseif ($a == $b) {
echo "a is equal to b";
} else {
echo "a is smaller than b";
}
?>
There may be severaI elseifs within the same if statement. The Iirst elseif expression (iI any) that evaIuates to
TRUE wouId be executed. In PHP, you can aIso write 'eIse iI' (in two words) and the behavior wouId be
identicaI to the one oI 'eIseiI' (in a singIe word). The syntactic meaning is sIightIy diIIerent (iI you're IamiIiar
with C, this is the same behavior) but the bottom Iine is that both wouId resuIt in exactIy the same behavior.
The elseif statement is onIy executed iI the preceding if expression and any preceding elseif expressions
evaIuated to FALSE, and the current elseif expression evaIuated to TRUE.
Alternative syntax for control structures
PHP oIIers an aIternative syntax Ior some oI its controI structures; nameIy, if, while, for, foreach, and switch.
In each case, the basic Iorm oI the aIternate syntax is to change the opening brace to a coIon (:) and the
cIosing brace to endif,, endwhile,, endfor,, endforeach,, or endswitch,, respectiveIy.
<?php if ($a == 5): ?>
A is equal to 5
<?php endif; ?>
In the above exampIe, the HTML bIock "A is equaI to 5" is nested within an if statement written in the
aIternative syntax. The HTML bIock wouId be dispIayed onIy iI Sa is equaI to 5.
The aIternative syntax appIies to else and elseif as weII. The IoIIowing is an if structure with elseif and else in
the aIternative Iormat:
<?php
if ($a == 5):
echo "a equals 5";
echo "...";
elseif ($a == 6):
echo "a equals 6";
echo "!!!";
else:
echo "a is neither 5 nor 6";
endif;
?>
2"0$#
while Ioops are the simpIest type oI Ioop in PHP. They behave just Iike their C counterparts. The basic Iorm oI
a while statement is:
while (expr)
statement
The meaning oI a while statement is simpIe. It teIIs PHP to execute the nested statement(s) repeatedIy, as Iong
as the while expression evaIuates to TRUE. The vaIue oI the expression is checked each time at the beginning
oI the Ioop, so even iI this vaIue changes during the execution oI the nested statement(s), execution wiII not
stop untiI the end oI the iteration (each time PHP runs the statements in the Ioop is one iteration). Sometimes,
iI the while expression evaIuates to FALSE Irom the very beginning, the nested statement(s) won't even be run
once.
Like with the if statement, you can group muItipIe statements within the same while Ioop by surrounding a
group oI statements with curIy braces, or by using the aIternate syntax:
while (expr):
statement
...
endwhile;
The IoIIowing exampIes are identicaI, and both print the numbers 1 through 10:
<?php
/* example 1 */
$i = 1;
while ($i <= 10) {
echo $i++; /* the printed value would be
$i before the increment
(post-increment) */
}
/* example 2 */
$i = 1;
while ($i <= 10):
echo $i;
$i++;
endwhile;
?>
3%42"0$#
do-while Ioops are very simiIar to while Ioops, except the truth expression is checked at the end oI each
iteration instead oI in the beginning. The main diIIerence Irom reguIar while Ioops is that the Iirst iteration oI
a do-while Ioop is guaranteed to run (the truth expression is onIy checked at the end oI the iteration), whereas
it's may not necessariIy run with a reguIar while Ioop (the truth expression is checked at the beginning oI each
iteration, iI it evaIuates to FALSE right Irom the beginning, the Ioop execution wouId end immediateIy).
There is just one syntax Ior do-while Ioops:
<?php
$i = 0;
do {
echo $i;
} while ($i > 0);
?>
The above Ioop wouId run one time exactIy, since aIter the Iirst iteration, when truth expression is checked, it
evaIuates to FALSE ($i is not bigger than 0) and the Ioop execution ends.
Advanced C users may be IamiIiar with a diIIerent usage oI the do-while Ioop, to aIIow stopping execution in
the middIe oI code bIocks, by encapsuIating them with do-while (0), and using the break statement. The
IoIIowing code Iragment demonstrates this:
<?php
do {
if ($i < 5) {
echo "i is not big enough";
break;
}
$i *= $factor;
if ($i < $minimum_limit) {
break;
}
echo "i is ok";
/* process i */
} while (0);
?>
Don't worry iI you don't understand this right away or at aII. You can code scripts and even powerIuI scripts
without using this 'Ieature'.
1%5
for Ioops are the most compIex Ioops in PHP. They behave Iike their C counterparts. The syntax oI a for Ioop
is:
for (expr1; expr2; expr3)
statement
The Iirst expression (expr1) is evaIuated (executed) once unconditionaIIy at the beginning oI the Ioop.
In the beginning oI each iteration, expr2 is evaIuated. II it evaIuates to TRUE, the Ioop continues and the nested
statement(s) are executed. II it evaIuates to FALSE, the execution oI the Ioop ends.
At the end oI each iteration, expr3 is evaIuated (executed).
Each oI the expressions can be empty or contain muItipIe expressions separated by commas. In expr2, aII
expressions separated by a comma are evaIuated but the resuIt is taken Irom the Iast part. expr2 being empty
means the Ioop shouId be run indeIiniteIy (PHP impIicitIy considers it as TRUE, Iike C). This may not be as
useIess as you might think, since oIten you'd want to end the Ioop using a conditionaI break statement instead
oI using the for truth expression.
Consider the IoIIowing exampIes. AII oI them dispIay the numbers 1 through 10:
<?php
/* example 1 */
for ($i = 1; $i <= 10; $i++) {
echo $i;
}
/* example 2 */
for ($i = 1; ; $i++) {
if ($i > 10) {
break;
}
echo $i;
}
/* example 3 */
$i = 1;
for (; ; ) {
if ($i > 10) {
break;
}
echo $i;
$i++;
}
/* example 4 */
for ($i = 1, $j = 0; $i <= 10; $j += $i, print $i, $i++);
?>
OI course, the Iirst exampIe appears to be the nicest one (or perhaps the Iourth), but you may Iind that being
abIe to use empty expressions in for Ioops comes in handy in many occasions.
PHP aIso supports the aIternate "coIon syntax" Ior for Ioops.
for (expr1; expr2; expr3):
statement
...
endfor;
1%5#67"
PHP 4 introduced a foreach construct, much Iike PerI and some other Ianguages. This simpIy gives an easy
way to iterate over arrays. foreach works onIy on arrays, and wiII issue an error when you try to use it on a
variabIe with a diIIerent data type or an uninitiaIized variabIe. There are two syntaxes; the second is a minor
but useIuI extension oI the Iirst:
foreach (array_expression as $value)
statement
foreach (array_expression as $key => $value)
statement
The Iirst Iorm Ioops over the array given by arravexpression. On each Ioop, the vaIue oI the current eIement
is assigned to Svalue and the internaI array pointer is advanced by one (so on the next Ioop, you'II be Iooking
at the next eIement).
The second Iorm does the same thing, except that the current eIement's key wiII be assigned to the variabIe
Skev on each Ioop.
As oI PHP 5, it is possibIe to iterate objects too.
Note: When foreach Iirst starts executing, the internaI array pointer is automaticaIIy reset to the Iirst eIement
oI the array. This means that you do not need to caII reset() beIore a foreach Ioop.
Note: UnIess the array is reIerenced, foreach operates on a copy oI the speciIied array and not the array itseII.
foreach has some side eIIects on the array pointer. Don't reIy on the array pointer during or aIter the Ioreach
without resetting it.
As oI PHP 5, you can easiIy modiIy array's eIements by preceding Svalue with &. This wiII assign reIerence
instead oI copying the vaIue.
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
?>
This is possibIe onIy iI iterated array can be reIerenced (i.e. is variabIe).
Warning
ReIerence oI a Svalue and the Iast array eIement remain even aIter the foreach Ioop. It is recommended to
destroy it by unset().
Note: foreach does not support the abiIity to suppress error messages using ''.
You may have noticed that the IoIIowing are IunctionaIIy identicaI:
<?php
$arr = array("one", "two", "three");
reset($arr);
while (list(, $value) = each($arr)) {
echo "Value: $value<br />\n";
}
foreach ($arr as $value) {
echo "Value: $value<br />\n";
}
?>
The IoIIowing are aIso IunctionaIIy identicaI:
<?php
$arr = array("one", "two", "three");
reset($arr);
while (list($key, $value) = each($arr)) {
echo "Key: $key; Value: $value<br />\n";
}
foreach ($arr as $key => $value) {
echo "Key: $key; Value: $value<br />\n";
}
?>
Some more exampIes to demonstrate usages:
<?php
/* foreach example 1: value only */
$a = array(1, 2, 3, 17);
foreach ($a as $v) {
echo "Current value of \$a: $v.\n";
}
/* foreach example 2: value (with key printed for illustration) */
$a = array(1, 2, 3, 17);
$i = 0; /* for illustrative purposes only */
foreach ($a as $v) {
echo "\$a[$i] => $v.\n";
$i++;
}
/* foreach example 3: key and value */
$a = array(
"one" => 1,
"two" => 2,
"three" => 3,
"seventeen" => 17
);
foreach ($a as $k => $v) {
echo "\$a[$k] => $v.\n";
}
/* foreach example 4: multi-dimensional arrays */
$a = array();
$a[0][0] = "a";
$a[0][1] = "b";
$a[1][0] = "y";
$a[1][1] = "z";
foreach ($a as $v1) {
foreach ($v1 as $v2) {
echo "$v2\n";
}
}
/* foreach example 5: dynamic arrays */
foreach (array(1, 2, 3, 4, 5) as $v) {
echo "$v\n";
}
?>
85#69
break ends execution oI the current for, foreach, while, do-while or switch structure.
break accepts an optionaI numeric argument which teIIs it how many nested encIosing structures are to be
broken out oI.
<?php
$arr = array('one', 'two', 'three', 'four', 'stop', 'five');
while (list(, $val) = each($arr)) {
if ($val == 'stop') {
break; /* You could also write 'break 1;' here. */
}
echo "$val<br />\n";
}
/* Using the optional argument. */
$i = 0;
while (++$i) {
switch ($i) {
case 5:
echo "At 5<br />\n";
break 1; /* Exit only the switch. */
case 10:
echo "At 10; quitting<br />\n";
break 2; /* Exit the switch and the while. */
default:
break;
}
}
?>
7%;<0;=#
continue is used within Iooping structures to skip the rest oI the current Ioop iteration and continue execution
at the condition evaIuation and then the beginning oI the next iteration.
Note: Note that in PHP the switch statement is considered a Iooping structure Ior the purposes oI continue.
continue accepts an optionaI numeric argument which teIIs it how many IeveIs oI encIosing Ioops it shouId
skip to the end oI.
<?php
while (list($key, $value) = each($arr)) {
if (!($key % 2)) { // skip odd members
continue;
}
do_something_odd($value);
}
$i = 0;
while ($i++ < 5) {
echo "Outer<br />\n";
while (1) {
echo "&nbsp;&nbsp;Middle<br />\n";
while (1) {
echo "&nbsp;&nbsp;Inner<br />\n";
continue 3;
}
echo "This never gets output.<br />\n";
}
echo "Neither does this.<br />\n";
}
?>
Omitting the semicoIon aIter continue can Iead to conIusion. Here's an exampIe oI what you shouIdn't do.
<?php
for ($i = 0; $i < 5; ++$i) {
if ($i == 2)
continue
print "$i\n";
}
?>
One can expect the resuIt to be :
0
1
3
4
but this script wiII output :
2
because the return vaIue oI the print() caII is int(1), and it wiII Iook Iike the optionaI numeric argument
mentioned above.
/20<7"
The switch statement is simiIar to a series oI IF statements on the same expression. In many occasions, you
may want to compare the same variabIe (or expression) with many diIIerent vaIues, and execute a diIIerent
piece oI code depending on which vaIue it equaIs to. This is exactIy what the switch statement is Ior.
Note: Note that unIike some other Ianguages, the continue statement appIies to switch and acts simiIar to
break. II you have a switch inside a Ioop and wish to continue to the next iteration oI the outer Ioop, use
continue 2.
Note: Note that switch/case does Ioose comparision.
The IoIIowing two exampIes are two diIIerent ways to write the same thing, one using a series oI if and elseif
statements, and the other using the switch statement:
Example 16.1. /20<7" structure
<?php
if ($i == 0) {
echo "i equals 0";
} elseif ($i == 1) {
echo "i equals 1";
} elseif ($i == 2) {
echo "i equals 2";
}
switch ($i) {
case 0:
echo "i equals 0";
break;
case 1:
echo "i equals 1";
break;
case 2:
echo "i equals 2";
break;
}
?>
Example 16.2. /20<7" structure allows usage of strings
<?php
switch ($i) {
case "apple":
echo "i is apple";
break;
case "bar":
echo "i is bar";
break;
case "cake":
echo "i is cake";
break;
}
?>
It is important to understand how the switch statement is executed in order to avoid mistakes. The switch
statement executes Iine by Iine (actuaIIy, statement by statement). In the beginning, no code is executed. OnIy
when a case statement is Iound with a vaIue that matches the vaIue oI the switch expression does PHP begin
to execute the statements. PHP continues to execute the statements untiI the end oI the switch bIock, or the
Iirst time it sees a break statement. II you don't write a break statement at the end oI a case's statement Iist,
PHP wiII go on executing the statements oI the IoIIowing case. For exampIe:
<?php
switch ($i) {
case 0:
echo "i equals 0";
case 1:
echo "i equals 1";
case 2:
echo "i equals 2";
}
?>
Here, iI Si is equaI to 0, PHP wouId execute aII oI the echo statements! II Si is equaI to 1, PHP wouId execute
the Iast two echo statements. You wouId get the expected behavior ('i equaIs 2' wouId be dispIayed) onIy iI Si
is equaI to 2. Thus, it is important not to Iorget break statements (even though you may want to avoid
suppIying them on purpose under certain circumstances).
In a switch statement, the condition is evaIuated onIy once and the resuIt is compared to each case statement.
In an elseif statement, the condition is evaIuated again. II your condition is more compIicated than a simpIe
compare and/or is in a tight Ioop, a switch may be Iaster.
The statement Iist Ior a case can aIso be empty, which simpIy passes controI into the statement Iist Ior the next
case.
<?php
switch ($i) {
case 0:
case 1:
case 2:
echo "i is less than 3 but not negative";
break;
case 3:
echo "i is 3";
}
?>
A speciaI case is the default case. This case matches anything that wasn't matched by the other cases. For
exampIe:
<?php
switch ($i) {
case 0:
echo "i equals 0";
break;
case 1:
echo "i equals 1";
break;
case 2:
echo "i equals 2";
break;
default:
echo "i is not equal to 0, 1 or 2";
}
?>
The case expression may be any expression that evaIuates to a simpIe type, that is, integer or IIoating-point
numbers and strings. Arrays or objects cannot be used here unIess they are dereIerenced to a simpIe type.
The aIternative syntax Ior controI structures is supported with switches. For more inIormation, see AIternative
syntax Ior controI structures.
<?php
switch ($i):
case 0:
echo "i equals 0";
break;
case 1:
echo "i equals 1";
break;
case 2:
echo "i equals 2";
break;
default:
echo "i is not equal to 0, 1 or 2";
endswitch;
?>
3#7$65#
The declare construct is used to set execution directives Ior a bIock oI code. The syntax oI declare is simiIar
to the syntax oI other IIow controI constructs:
declare (directive)
statement
The directive section aIIows the behavior oI the declare bIock to be set. CurrentIy onIy one directive is
recognized: the ticks directive. (See beIow Ior more inIormation on the ticks directive)
The statement part oI the declare bIock wiII be executed -- how it is executed and what side eIIects occur
during execution may depend on the directive set in the directive bIock.
The declare construct can aIso be used in the gIobaI scope, aIIecting aII code IoIIowing it.
<?php
// these are the same:
// you can use this:
declare(ticks=1) {
// entire script here
}
// or you can use this:
declare(ticks=1);
// entire script here
?>
Ticks
A tick is an event that occurs Ior every N Iow-IeveI statements executed by the parser within the declare
bIock. The vaIue Ior N is speciIied using ticks=N within the declare bIocks's directive section.
The event(s) that occur on each tick are speciIied using the registertickIunction(). See the exampIe beIow
Ior more detaiIs. Note that more than one event can occur Ior each tick.
Example 16.3. Profile a section of PHP code
<?php
// A function that records the time when it is called
function profile($dump = FALSE)
{
static $profile;
// Return the times stored in profile, then erase it
if ($dump) {
$temp = $profile;
unset($profile);
return $temp;
}
$profile[] = microtime();
}
// Set up a tick handler
register_tick_function("profile");
// Initialize the function before the declare block
profile();
// Run a block of code, throw a tick every 2nd statement
declare(ticks=2) {
for ($x = 1; $x < 50; ++$x) {
echo similar_text(md5($x), md5($x*$x)), "<br />;";
}
}
// Display the data stored in the profiler
print_r(profile(TRUE));
?>
The example profiles the PHP code within the 'declare' block, recording the time at
which every second low-level statement in the block was executed. This information
can then be used to find the slow areas within particular segments of code. This
process can be performed using other methods: using ticks is more convenient and
easier to implement.
Ticks are weII suited Ior debugging, impIementing simpIe muItitasking, background I/O and many other tasks.
return
II caIIed Irom within a Iunction, the return() statement immediateIy ends execution oI the current Iunction,
and returns its argument as the vaIue oI the Iunction caII. return() wiII aIso end the execution oI an evaI()
statement or script IiIe.
II caIIed Irom the gIobaI scope, then execution oI the current script IiIe is ended. II the current script IiIe was
incIude()ed or require()ed, then controI is passed back to the caIIing IiIe. Furthermore, iI the current script IiIe
was incIude()ed, then the vaIue given to return() wiII be returned as the vaIue oI the incIude() caII. II return()
is caIIed Irom within the main script IiIe, then script execution ends. II the current script IiIe was named by the
autoprependIiIe or autoappendIiIe conIiguration options in php.ini, then that script IiIe's execution is
ended.
For more inIormation, see Returning vaIues.
Note: Note that since return() is a Ianguage construct and not a Iunction, the parentheses surrounding its
arguments are not required. It is common to Ieave them out, and you actuaIIy shouId do so as PHP has Iess
work to do in this case.
Note: You shouId never use parentheses around your return variabIe when returning by reIerence, as this wiII
not work. You can onIy return variabIes by reIerence, not the resuIt oI a statement. II you use return (Sa), then
you're not returning a variabIe, but the resuIt oI the expression (Sa) (which is, oI course, the vaIue oI Sa).
require()
The require() statement incIudes and evaIuates the speciIic IiIe.
require() incIudes and evaIuates a speciIic IiIe. DetaiIed inIormation on how this incIusion works is described
in the documentation Ior incIude().
require() and incIude() are identicaI in every way except how they handIe IaiIure. They both produce a
Warning, but require() resuIts in a FataI Error. In other words, don't hesitate to use require() iI you want a
missing IiIe to haIt processing oI the page. incIude() does not behave this way, the script wiII continue
regardIess. Be sure to have an appropriate incIudepath setting as weII.
Example 16.4. Basic require() examples
<?php
require 'prepend.php';
require $somefile;
require ('somefile.txt');
?>
See the incIude() documentation Ior more exampIes.
Note: Prior to PHP 4.0.2, the IoIIowing appIies: require() wiII aIways attempt to read the target IiIe, even iI
the Iine it's on never executes. The conditionaI statement won't aIIect require(). However, iI the Iine on which
the require() occurs is not executed, neither wiII any oI the code in the target IiIe be executed. SimiIarIy,
Iooping structures do not aIIect the behaviour oI require(). AIthough the code contained in the target IiIe is
stiII subject to the Ioop, the require() itseII happens onIy once.
Note: Because this is a Ianguage construct and not a Iunction, it cannot be caIIed using variabIe Iunctions
Warning
Windows versions oI PHP prior to PHP 4.3.0 do not support accessing remote IiIes via this Iunction, even iI
aIIowurIIopen is enabIed.
include()
The include() statement incIudes and evaIuates the speciIied IiIe.
The documentation beIow aIso appIies to require(). The two constructs are identicaI in every way except how
they handIe IaiIure. They both produce a Warning, but require() resuIts in a FataI Error. In other words, use
require() iI you want a missing IiIe to haIt processing oI the page. include() does not behave this way, the
script wiII continue regardIess. Be sure to have an appropriate incIudepath setting as weII. Be warned that
parse error in incIuded IiIe doesn't cause processing haIting in PHP versions prior to PHP 4.3.5. Since this
version, it does.
FiIes Ior incIuding are Iirst Iooked Ior in each incIudepath entry reIative to the current working directory, and
then in the directory oI current script. E.g. iI your incIudepath is libraries, current working directory is
www, you incIuded includea.php and there is include "b.php" in that IiIe, b.php is Iirst Iooked in
wwwlibraries and then in wwwinclude. II IiIename begins with . or .., it is Iooked onIy in the current
working directory.
When a IiIe is incIuded, the code it contains inherits the variabIe scope oI the Iine on which the incIude
occurs. Any variabIes avaiIabIe at that Iine in the caIIing IiIe wiII be avaiIabIe within the caIIed IiIe, Irom that
point Iorward. However, aII Iunctions and cIasses deIined in the incIuded IiIe have the gIobaI scope.
Example 16.5. Basic include() example
vars.php
<?php
$color = 'green';
$fruit = 'apple';
?>
test.php
<?php
echo "A $color $fruit"; // A
include 'vars.php';
echo "A $color $fruit"; // A green apple
?>
II the incIude occurs inside a Iunction within the caIIing IiIe, then aII oI the code contained in the caIIed IiIe
wiII behave as though it had been deIined inside that Iunction. So, it wiII IoIIow the variabIe scope oI that
Iunction. An exception to this ruIe are magic constants which are evaIuated by the parser beIore the incIude
occurs.
Example 16.6. Including within functions
<?php
function foo()
{
global $color;
include 'vars.php';
echo "A $color $fruit";
}
/* vars.php is in the scope of foo() so *
* $fruit is NOT available outside of this *
* scope. $color is because we declared it *
* as global. */
foo(); // A green apple
echo "A $color $fruit"; // A green
?>
When a IiIe is incIuded, parsing drops out oI PHP mode and into HTML mode at the beginning oI the target
IiIe, and resumes again at the end. For this reason, any code inside the target IiIe which shouId be executed as
PHP code must be encIosed within vaIid PHP start and end tags.
II "URL Iopen wrappers" are enabIed in PHP (which they are in the deIauIt conIiguration), you can speciIy
the IiIe to be incIuded using a URL (via HTTP or other supported wrapper - see Appendix O, List of
Supported Protocolshrappers Ior a Iist oI protocoIs) instead oI a IocaI pathname. II the target server
interprets the target IiIe as PHP code, variabIes may be passed to the incIuded IiIe using a URL request string
as used with HTTP GET. This is not strictIy speaking the same thing as incIuding the IiIe and having it inherit
the parent IiIe's variabIe scope; the script is actuaIIy being run on the remote server and the resuIt is then being
incIuded into the IocaI script.
Warning
Windows versions oI PHP prior to PHP 4.3.0 do not support accessing remote IiIes via this Iunction, even iI
aIIowurIIopen is enabIed.
Example 16.7. include() through HTTP
<?php
/* This example assumes that www.example.com is configured to parse .php
* files and not .txt files. Also, 'Works' here means that the variables
* $foo and $bar are available within the included file. */
// Won't work; file.txt wasn't handled by www.example.com as PHP
include 'http://www.example.com/file.txt?foo=1&bar=2';
// Won't work; looks for a file named 'file.php?foo=1&bar=2' on the
// local filesystem.
include 'file.php?foo=1&bar=2';
// Works.
include 'http://www.example.com/file.php?foo=1&bar=2';
$foo = 1;
$bar = 2;
include 'file.txt'; // Works.
include 'file.php'; // Works.
?>
Security warning
Remote IiIe may be processed at the remote server (depending on the IiIe extension and the Iact iI the remote
server runs PHP or not) but it stiII has to produce a vaIid PHP script because it wiII be processed at the IocaI
server. II the IiIe Irom the remote server shouId be processed there and outputted onIy, readIiIe() is much
better Iunction to use. Otherwise, speciaI care shouId be taken to secure the remote script to produce a vaIid
and desired code.
See aIso Remote IiIes, Iopen() and IiIe() Ior reIated inIormation.
HandIing Returns: It is possibIe to execute a return() statement inside an incIuded IiIe in order to terminate
processing in that IiIe and return to the script which caIIed it. AIso, it's possibIe to return vaIues Irom incIuded
IiIes. You can take the vaIue oI the incIude caII as you wouId a normaI Iunction. This is not, however, possibIe
when incIuding remote IiIes unIess the output oI the remote IiIe has vaIid PHP start and end tags (as with any
IocaI IiIe). You can decIare the needed variabIes within those tags and they wiII be introduced at whichever
point the IiIe was incIuded.
Because include() is a speciaI Ianguage construct, parentheses are not needed around its argument. Take care
when comparing return vaIue.
Example 16.8. Comparing return value of include
<?php
// won't work, evaluated as include(('vars.php') == 'OK'), i.e. include('')
if (include('vars.php') == 'OK') {
echo 'OK';
}
// works
if ((include 'vars.php') == 'OK') {
echo 'OK';
}
?>
Note: In PHP 3, the return may not appear inside a bIock unIess it's a Iunction bIock, in which case the
return() appIies to that Iunction and not the whoIe IiIe.
Example 16.9. include() and the return() statement
return.php
<?php
$var = 'PHP';
return $var;
?>
noreturn.php
<?php
$var = 'PHP';
?>
testreturns.php
<?php
$foo = include 'return.php';
echo $foo; // prints 'PHP'
$bar = include 'noreturn.php';
echo $bar; // prints 1
?>
Sbar is the vaIue 1 because the incIude was successIuI. Notice the diIIerence between the above exampIes.
The Iirst uses return() within the incIuded IiIe whiIe the other does not. II the IiIe can't be incIuded, FALSE is
returned and EhARNING is issued.
II there are Iunctions deIined in the incIuded IiIe, they can be used in the main IiIe independent iI they are
beIore return() or aIter. II the IiIe is incIuded twice, PHP 5 issues IataI error because Iunctions were aIready
decIared, whiIe PHP 4 doesn't compIain about Iunctions deIined aIter return(). It is recommended to use
incIudeonce() instead oI checking iI the IiIe was aIready incIuded and conditionaIIy return inside the
incIuded IiIe.
Another way to "incIude" a PHP IiIe into a variabIe is to capture the output by using the Output ControI
Functions with include(). For exampIe:
Example 16.10. Using output buffering to include a PHP file into a string
<?php
$string = get_include_contents('somefile.php');
function get_include_contents($filename) {
if (is_file($filename)) {
ob_start();
include $filename;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
return false;
}
?>
In order to automaticaIIy incIude IiIes within scripts, see aIso the autoprependIiIe and autoappendIiIe
conIiguration options in php.ini.
Note: Because this is a Ianguage construct and not a Iunction, it cannot be caIIed using variabIe Iunctions
require_once()
The require_once() statement incIudes and evaIuates the speciIied IiIe during the execution oI the script. This
is a behavior simiIar to the require() statement, with the onIy diIIerence being that iI the code Irom a IiIe has
aIready been incIuded, it wiII not be incIuded again. See the documentation Ior require() Ior more inIormation
on how this statement works.
require_once() shouId be used in cases where the same IiIe might be incIuded and evaIuated more than once
during a particuIar execution oI a script, and you want to be sure that it is incIuded exactIy once to avoid
probIems with Iunction redeIinitions, variabIe vaIue reassignments, etc.
For exampIes on using require_once() and incIudeonce(), Iook at the PEAR code incIuded in the Iatest
PHP source code distributions.
Return vaIues are the same as with incIude(). II the IiIe was aIready incIuded, this Iunction returns TRUE
Note: require_once() was added in PHP 4.0.1
Note: Be aware, that the behaviour oI require_once() and incIudeonce() may not be what you expect on a
non case sensitive operating system (such as Windows).
Example 16.11. require_once() is case insensitive on Windows
<?php
require_once "a.php"; // this will include a.php
require_once "A.php"; // this will include a.php again on Windows! (PHP 4 only)
?>
This behaviour changed in PHP 5 - the path is normaIized Iirst so that C.PROGRA~1A.php is reaIized the
same as C.Program Filesa.php and the IiIe is required just once.
Warning
Windows versions oI PHP prior to PHP 4.3.0 do not support accessing remote IiIes via this Iunction, even iI
aIIowurIIopen is enabIed.
include_once()
The include_once() statement incIudes and evaIuates the speciIied IiIe during the execution oI the script. This
is a behavior simiIar to the incIude() statement, with the onIy diIIerence being that iI the code Irom a IiIe has
aIready been incIuded, it wiII not be incIuded again. As the name suggests, it wiII be incIuded just once.
include_once() shouId be used in cases where the same IiIe might be incIuded and evaIuated more than once
during a particuIar execution oI a script, and you want to be sure that it is incIuded exactIy once to avoid
probIems with Iunction redeIinitions, variabIe vaIue reassignments, etc.
For more exampIes on using requireonce() and include_once(), Iook at the PEAR code incIuded in the
Iatest PHP source code distributions.
Return vaIues are the same as with incIude(). II the IiIe was aIready incIuded, this Iunction returns TRUE
Note: include_once() was added in PHP 4.0.1
Note: Be aware, that the behaviour oI include_once() and requireonce() may not be what you expect on a
non case sensitive operating system (such as Windows).
Example 16.12. include_once() is case insensitive on Windows
<?php
include_once "a.php"; // this will include a.php
include_once "A.php"; // this will include a.php again on Windows! (PHP 4 only)
?>
This behaviour changed in PHP 5 - the path is normaIized Iirst so that C.PROGRA~1A.php is reaIized the
same as C.Program Filesa.php and the IiIe is incIuded just once.
Warning
Windows versions oI PHP prior to PHP 4.3.0 do not support accessing remote IiIes via this Iunction, even iI
aIIowurIIopen is enabIed.
Chapter 17. Functions
User-defined functions
A Iunction may be deIined using syntax such as the IoIIowing:
Example 17.1. Pseudo code to demonstrate function uses
<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
echo "Example function.\n";
return $retval;
}
?>
Any vaIid PHP code may appear inside a Iunction, even other Iunctions and cIass deIinitions.
Function names IoIIow the same ruIes as other IabeIs in PHP. A vaIid Iunction name starts with a Ietter or
underscore, IoIIowed by any number oI Ietters, numbers, or underscores. As a reguIar expression, it wouId be
expressed thus: [a-:A-Zx7f-xff{[a-:A-Z0-9x7f-xff{*.
Tip
You may aIso want to take a Iook at the Appendix T, Userland Naming Guide.
In PHP 3, Iunctions must be deIined beIore they are reIerenced. No such requirement exists since PHP 4.
Except when a Iunction is conditionaIIy deIined such as shown in the two exampIes beIow.
When a Iunction is deIined in a conditionaI manner such as the two exampIes shown. Its deIinition must be
processed prior to being caIIed.
Example 17.2. Conditional functions
<?php
$makefoo = true;
/* We can't call foo() from here
since it doesn't exist yet,
but we can call bar() */
bar();
if ($makefoo) {
function foo()
{
echo "I don't exist until program execution reaches me.\n";
}
}
/* Now we can safely call foo()
since $makefoo evaluated to true */
if ($makefoo) foo();
function bar()
{
echo "I exist immediately upon program start.\n";
}
?>
Example 17.3. Functions within functions
<?php
function foo()
{
function bar()
{
echo "I don't exist until foo() is called.\n";
}
}
/* We can't call bar() yet
since it doesn't exist. */
foo();
/* Now we can call bar(),
foo()'s processesing has
made it accessible. */
bar();
?>
AII Iunctions and cIasses in PHP have the gIobaI scope - they can be caIIed outside a Iunction even iI they
were deIined inside and vice versa.
PHP does not support Iunction overIoading, nor is it possibIe to undeIine or redeIine previousIy-decIared
Iunctions.
Note: Function names are case-insensitive, though it is usuaIIy good Iorm to caII Iunctions as they appear in
their decIaration.
PHP 3 does not support variabIe numbers oI arguments to Iunctions, aIthough deIauIt arguments are supported
(see DeIauIt argument vaIues Ior more inIormation). Both are supported, as oI PHP 4: see VariabIe-Iength
argument Iists and the Iunction reIerences Ior Iuncnumargs(), Iuncgetarg(), and Iuncgetargs() Ior more
inIormation.
It is possibIe to caII recursive Iunctions in PHP. However avoid recursive Iunction/method caIIs with over
100-200 recursion IeveIs as it can smash the stack and cause a termination oI the current script.
Example 17.4. Recursive functions
<?php
function recursion($a)
{
if ($a < 20) {
echo "$a\n";
recursion($a + 1);
}
}
?>
Function arguments
InIormation may be passed to Iunctions via the argument Iist, which is a comma-deIimited Iist oI expressions.
PHP supports passing arguments by vaIue (the deIauIt), passing by reIerence, and deIauIt argument vaIues.
VariabIe-Iength argument Iists are supported onIy in PHP 4 and Iater; see VariabIe-Iength argument Iists and
the Iunction reIerences Ior Iuncnumargs(), Iuncgetarg(), and Iuncgetargs() Ior more inIormation. A
simiIar eIIect can be achieved in PHP 3 by passing an array oI arguments to a Iunction:
Example 17.5. Passing arrays to functions
<?php
function takes_array($input)
{
echo "$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>
Making arguments be passed by reference
By deIauIt, Iunction arguments are passed by vaIue (so that iI you change the vaIue oI the argument within the
Iunction, it does not get changed outside oI the Iunction). II you wish to aIIow a Iunction to modiIy its
arguments, you must pass them by reIerence.
II you want an argument to a Iunction to aIways be passed by reIerence, you can prepend an ampersand (&) to
the argument name in the Iunction deIinition:
Example 17.6. Passing function parameters by reference
<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // outputs 'This is a string, and something extra.'
?>
Default argument values
A Iunction may deIine C-styIe deIauIt vaIues Ior scaIar arguments as IoIIows:
Example 17.7. Use of default parameters in functions
<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>
The output Irom the above snippet is:
Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.
AIso PHP aIIows you to use arrays and speciaI type NULL as deIauIt vaIues, Ior exampIe:
Example 17.8. Using non-scalar types as default values
<?php
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee();
echo makecoffee(array("cappuccino", "lavazza"), "teapot");
?>
The deIauIt vaIue must be a constant expression, not (Ior exampIe) a variabIe, a cIass member or a Iunction
caII.
Note that when using deIauIt arguments, any deIauIts shouId be on the right side oI any non-deIauIt
arguments; otherwise, things wiII not work as expected. Consider the IoIIowing code snippet:
Example 17.9. Incorrect usage of default function arguments
<?php
function makeyogurt($type = "acidophilus", $flavour)
{
return "Making a bowl of $type $flavour.\n";
}
echo makeyogurt("raspberry"); // won't work as expected
?>
The output oI the above exampIe is:
Warning: Missing argument 2 in call to makeyogurt() in
/usr/local/etc/httpd/htdocs/php3test/functest.html on line 41
Making a bowl of raspberry .
Now, compare the above with this:
Example 17.10. Correct usage of default function arguments
<?php
function makeyogurt($flavour, $type = "acidophilus")
{
return "Making a bowl of $type $flavour.\n";
}
echo makeyogurt("raspberry"); // works as expected
?>
The output oI this exampIe is:
Making a bowl of acidophilus raspberry.
Note: As oI PHP 5, deIauIt vaIues may be passed by reIerence.
Variable-length argument lists
PHP 4 and above has support Ior variabIe-Iength argument Iists in user-deIined Iunctions. This is reaIIy quite
easy, using the Iuncnumargs(), Iuncgetarg(), and Iuncgetargs() Iunctions.
No speciaI syntax is required, and argument Iists may stiII be expIicitIy provided with Iunction deIinitions and
wiII behave as normaI.
Returning values
VaIues are returned by using the optionaI return statement. Any type may be returned, incIuding Iists and
objects. This causes the Iunction to end its execution immediateIy and pass controI back to the Iine Irom
which it was caIIed. See return() Ior more inIormation.
Example 17.11. Use of return()
<?php
function square($num)
{
return $num * $num;
}
echo square(4); // outputs '16'.
?>
You can't return muItipIe vaIues Irom a Iunction, but simiIar resuIts can be obtained by returning a Iist.
Example 17.12. Returning an array to get multiple values
<?php
function small_numbers()
{
return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
?>
To return a reIerence Irom a Iunction, you have to use the reIerence operator & in both the Iunction
decIaration and when assigning the returned vaIue to a variabIe:
Example 17.13. Returning a reference from a function
<?php
function &returns_reference()
{
return $someref;
}
$newref =& returns_reference();
?>
For more inIormation on reIerences, pIease check out ReIerences ExpIained.
Variable functions
PHP supports the concept oI variabIe Iunctions. This means that iI a variabIe name has parentheses appended
to it, PHP wiII Iook Ior a Iunction with the same name as whatever the variabIe evaIuates to, and wiII attempt
to execute it. Among other things, this can be used to impIement caIIbacks, Iunction tabIes, and so Iorth.
VariabIe Iunctions won't work with Ianguage constructs such as echo(), print(), unset(), isset(), empty(),
incIude(), require() and the Iike. You need to use your own wrapper Iunction to utiIize any oI these constructs
as variabIe Iunctions.
Example 17.14. Variable function example
<?php
function foo() {
echo "In foo()<br />\n";
}
function bar($arg = '')
{
echo "In bar(); argument was '$arg'.<br />\n";
}
// This is a wrapper function around echo
function echoit($string)
{
echo $string;
}
$func = 'foo';
$func(); // This calls foo()
$func = 'bar';
$func('test'); // This calls bar()
$func = 'echoit';
$func('test'); // This calls echoit()
?>
You can aIso caII an object's method by using the variabIe Iunctions Ieature.
Example 17.15. Variable method example
<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // This calls the Bar() method
}
function Bar()
{
echo "This is Bar";
}
}
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // This calls $foo->Variable()
?>
See aIso caIIuserIunc(), variabIe variabIes and Iunctionexists().
Internal (built-in) functions
PHP comes standard with many Iunctions and constructs. There are aIso Iunctions that require speciIic PHP
extensions compiIed in otherwise you'II get IataI "undeIined Iunction" errors. For exampIe, to use image
Iunctions such as imagecreatetruecoIor(), you'II need your PHP compiIed with GD support. Or, to use
mysqIconnect() you'II need your PHP compiIed in with MySQL support. There are many core Iunctions that
are incIuded in every version oI PHP Iike the string and variabIe Iunctions. A caII to phpinIo() or
getIoadedextensions() wiII show you which extensions are Ioaded into your PHP. AIso note that many
extensions are enabIed by deIauIt and that the PHP manuaI is spIit up by extension. See the conIiguration,
instaIIation, and individuaI extension chapters, Ior inIormation on how to setup your PHP.
Reading and understanding a Iunction's prototype is expIained within the manuaI section titIed how to read a
Iunction deIinition. It's important to reaIize what a Iunction returns or iI a Iunction works directIy on a passed
in vaIue. For exampIe, strrepIace() wiII return the modiIied string whiIe usort() works on the actuaI passed in
variabIe itseII. Each manuaI page aIso has speciIic inIormation Ior each Iunction Iike inIormation on Iunction
parameters, behavior changes, return vaIues Ior both success and IaiIure, and avaiIabiIity inIormation.
Knowing these important (yet oIten subtIe) diIIerences is cruciaI Ior writing correct PHP code.
Note: II the parameters given to a Iunction are not what it expects, such as passing an array where a string is
expected, the return vaIue oI the Iunction is undeIined. In this case it wiII IikeIy return NULL but this is just a
convention, and cannot be reIied upon.
Chapter 18. Classes and Objects (PHP 4)
7$6//
A cIass is a coIIection oI variabIes and Iunctions working with these variabIes. VariabIes are deIined by var
and Iunctions by function. A cIass is deIined using the IoIIowing syntax:
<?php
class Cart {
var $items; // Items in our shopping cart
// Add $num articles of $artnr to the cart
function add_item($artnr, $num) {
$this->items[$artnr] += $num;
}
// Take $num articles of $artnr out of the cart
function remove_item($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} elseif ($this->items[$artnr] == $num) {
unset($this->items[$artnr]);
return true;
} else {
return false;
}
}
}
?>
This deIines a cIass named Cart that consists oI an associative array oI articIes in the cart and two Iunctions to
add and remove items Irom this cart.
Warning
You can NOT break up a cIass deIinition into muItipIe IiIes. You aIso can NOT break a cIass deIinition into
muItipIe PHP bIocks, unIess the break is within a method decIaration. The IoIIowing wiII not work:
<?php
class test {
?>
<?php
function test() {
print 'OK';
}
}
?>
However, the IoIIowing is aIIowed:
<?php
class test {
function test() {
?>
<?php
print 'OK';
}
}
?>
The IoIIowing cautionary notes are vaIid Ior PHP 4.
Caution
The name stdClass is used internaIIy by Zend and is reserved. You cannot have a cIass named stdClass in
PHP.
Caution
The Iunction names sleep and wakeup are magicaI in PHP cIasses. You cannot have Iunctions with these
names in any oI your cIasses unIess you want the magic IunctionaIity associated with them. See beIow Ior
more inIormation.
Caution
PHP reserves aII Iunction names starting with as magicaI. It is recommended that you do not use Iunction
names with in PHP unIess you want some documented magic IunctionaIity.
In PHP 4, onIy constant initiaIizers Ior var variabIes are aIIowed. To initiaIize variabIes with non-constant
vaIues, you need an initiaIization Iunction which is caIIed automaticaIIy when an object is being constructed
Irom the cIass. Such a Iunction is caIIed a constructor (see beIow).
<?php
class Cart {
/* None of these will work in PHP 4. */
var $todays_date = date("Y-m-d");
var $name = $firstname;
var $owner = 'Fred ' . 'Jones';
/* Arrays containing constant values will, though. */
var $items = array("VCR", "TV");
}
/* This is how it should be done. */
class Cart {
var $todays_date;
var $name;
var $owner;
var $items = array("VCR", "TV");
function Cart() {
$this->todays_date = date("Y-m-d");
$this->name = $GLOBALS['firstname'];
/* etc. . . */
}
}
?>
CIasses are types, that is, they are bIueprints Ior actuaI variabIes. You have to create a variabIe oI the desired
type with the new operator.
<?php
$cart = new Cart;
$cart->add_item("10", 1);
$another_cart = new Cart;
$another_cart->add_item("0815", 3);
?>
This creates the objects Scart and Sanothercart, both oI the cIass Cart. The Iunction additem() oI the Scart
object is being caIIed to add 1 item oI articIe number 10 to the Scart. 3 items oI articIe number 0815 are being
added to Sanothercart.
Both, Scart and Sanothercart, have Iunctions additem(), removeitem() and a variabIe items. These are
distinct Iunctions and variabIes. You can think oI the objects as something simiIar to directories in a
IiIesystem. In a IiIesystem you can have two diIIerent IiIes README.TXT, as Iong as they are in diIIerent
directories. Just Iike with directories where you'II have to type the IuII pathname in order to reach each IiIe
Irom the topIeveI directory, you have to speciIy the compIete name oI the Iunction you want to caII: in PHP
terms, the topIeveI directory wouId be the gIobaI namespace, and the pathname separator wouId be -. Thus,
the names Scart-items and Sanothercart-items name two diIIerent variabIes. Note that the variabIe is
named Scart-items, not Scart-Sitems, that is, a variabIe name in PHP has onIy a singIe doIIar sign.
<?php
// correct, single $
$cart->items = array("10" => 1);
// invalid, because $cart->$items becomes $cart->""
$cart->$items = array("10" => 1);
// correct, but may or may not be what was intended:
// $cart->$myvar becomes $cart->items
$myvar = 'items';
$cart->$myvar = array("10" => 1);
?>
Within a cIass deIinition, you do not know under which name the object wiII be accessibIe in your program: at
the time the Cart cIass was written, it was unknown whether the object wouId be named Scart, Sanothercart,
or something eIse Iater. Thus, you cannot write Scart-items within the Cart cIass itseII. Instead, in order to be
abIe to access its own Iunctions and variabIes Irom within a cIass, one can use the pseudo-variabIe Sthis which
can be read as 'my own' or 'current object'. Thus, 'Sthis-items[Sartnr{ Snum' can be read as 'add Snum to
the Sartnr counter oI my own items array' or 'add Snum to the Sartnr counter oI the items array within the
current object'.
Note: The Sthis pseudo-variabIe is not usuaIIy deIined iI the method in which it is hosted is caIIed staticaIIy.
This is not, however, a strict ruIe: Sthis is deIined iI a method is caIIed staticaIIy Irom within another object.
In this case, the vaIue oI Sthis is that oI the caIIing object. This is iIIustrated in the IoIIowing exampIe:
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this is not defined.\n";
}
}
}
class B
{
function bar()
{
A::foo();
}
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
The above exampIe wiII output:
$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.
Note: There are some nice Iunctions to handIe cIasses and objects. You might want to take a Iook at the
CIass/Object Functions.
#><#;3/
OIten you need cIasses with simiIar variabIes and Iunctions to another existing cIass. In Iact, it is good
practice to deIine a generic cIass which can be used in aII your projects and adapt this cIass Ior the needs oI
each oI your speciIic projects. To IaciIitate this, cIasses can be extensions oI other cIasses. The extended or
derived cIass has aII variabIes and Iunctions oI the base cIass (this is caIIed 'inheritance' despite the Iact that
nobody died) and what you add in the extended deIinition. It is not possibIe to subtract Irom a cIass, that is, to
undeIine any existing Iunctions or variabIes. An extended cIass is aIways dependent on a singIe base cIass,
that is, muItipIe inheritance is not supported. CIasses are extended using the keyword 'extends'.
<?php
class Named_Cart extends Cart {
var $owner;
function set_owner ($name) {
$this->owner = $name;
}
}
?>
This deIines a cIass NamedCart that has aII variabIes and Iunctions oI Cart pIus an additionaI variabIe
Sowner and an additionaI Iunction setowner(). You create a named cart the usuaI way and can now set and
get the carts owner. You can stiII use normaI cart Iunctions on named carts:
<?php
$ncart = new Named_Cart; // Create a named cart
$ncart->set_owner("kris"); // Name that cart
print $ncart->owner; // print the cart owners name
$ncart->add_item("10", 1); // (inherited functionality from cart)
?>
This is aIso caIIed a "parent-chiId" reIationship. You create a cIass, parent, and use extends to create a new
cIass based on the parent cIass: the chiId cIass. You can even use this new chiId cIass and create another cIass
based on this chiId cIass.
Note: CIasses must be deIined beIore they are used! II you want the cIass NamedCart to extend the cIass
Cart, you wiII have to deIine the cIass Cart Iirst. II you want to create another cIass caIIed
Yellownamedcart based on the cIass NamedCart you have to deIine NamedCart Iirst. To make it short:
the order in which the cIasses are deIined is important.
Constructors
Constructors are Iunctions in a cIass that are automaticaIIy caIIed when you create a new instance oI a cIass
with new. A Iunction becomes a constructor, when it has the same name as the cIass. II a cIass has no
constructor, the constructor oI the base cIass wiII be caIIed, iI it exists.
<?php
class Auto_Cart extends Cart {
function Auto_Cart() {
$this->add_item("10", 1);
}
}
?>
This deIines a cIass AutoCart that is a Cart pIus a constructor which initiaIizes the cart with one item oI
articIe number "10" each time a newAutoCart is being made with "new". Constructors can take arguments
and these arguments can be optionaI, which makes them much more useIuI. To be abIe to stiII use the cIass
without parameters, aII parameters to constructors shouId be made optionaI by providing deIauIt vaIues.
<?php
class Constructor_Cart extends Cart {
function Constructor_Cart($item = "10", $num = 1) {
$this->add_item ($item, $num);
}
}
// Shop the same old boring stuff.
$default_cart = new Constructor_Cart;
// Shop for real...
$different_cart = new Constructor_Cart("20", 17);
?>
You aIso can use the operator to mute errors occurring in the constructor, e.g. new.
<?php
class A
{
function A()
{
echo "I am the constructor of A.<br />\n";
}
function B()
{
echo "I am a regular function named B in class A.<br />\n";
echo "I am not a constructor in A.<br />\n";
}
}
class B extends A
{
}
// This will call B() as a constructor
$b = new B;
?>
The Iunction B() in cIass AwiII suddenIy become a constructor in cIass B, aIthough it was never intended to
be. PHP 4 does not care iI the Iunction is being deIined in cIass B, or iI it has been inherited.
Caution
PHP 4 doesn't caII constructors oI the base cIass automaticaIIy Irom a constructor oI a derived cIass. It is your
responsibiIity to propagate the caII to constructors upstream where appropriate.
Destructors are Iunctions that are caIIed automaticaIIy when an object is destroyed, either with unset() or by
simpIy going out oI scope. There are no destructors in PHP. You may use registershutdownIunction()
instead to simuIate most eIIects oI destructors.
Scope Resolution Operator (??)
Caution
The IoIIowing is vaIid Ior PHP 4 and Iater onIy.
Sometimes it is useIuI to reIer to Iunctions and variabIes in base cIasses or to reIer to Iunctions in cIasses that
have not yet any instances. The :: operator is being used Ior this.
<?php
class A {
function example() {
echo "I am the original function A::example().<br />\n";
}
}
class B extends A {
function example() {
echo "I am the redefined function B::example().<br />\n";
A::example();
}
}
// there is no object of class A.
// this will print
// I am the original function A::example().<br />
A::example();
// create an object of class B.
$b = new B;
// this will print
// I am the redefined function B::example().<br />
// I am the original function A::example().<br />
$b->example();
?>
The above exampIe caIIs the Iunction exampIe() in cIass A, but there is no object oI cIass A, so that we cannot
write $a->exampIe() or simiIar. Instead we caII exampIe() as a 'cIass Iunction', that is, as a Iunction oI the cIass
itseII, not any object oI that cIass.
There are cIass Iunctions, but there are no cIass variabIes. In Iact, there is no object at aII at the time oI the
caII. Thus, a cIass Iunction may not use any object variabIes (but it can use IocaI and gIobaI variabIes), and it
may not use Sthis at aII.
In the above exampIe, cIass B redeIines the Iunction exampIe(). The originaI deIinition in cIass A is shadowed
and no Ionger avaiIabIe, unIess you are reIerring speciIicaIIy to the impIementation oI exampIe() in cIass A
using the ::-operator. Write A::exampIe() to do this (in Iact, you shouId be writing parent::exampIe(), as shown
in the next section).
In this context, there is a current object and it may have object variabIes. Thus, when used Irom WITHIN an
object Iunction, you may use Sthis and object variabIes.
'65#;<
You may Iind yourseII writing code that reIers to variabIes and Iunctions in base cIasses. This is particuIarIy
true iI your derived cIass is a reIinement or speciaIisation oI code in your base cIass.
Instead oI using the IiteraI name oI the base cIass in your code, you shouId be using the speciaI name parent,
which reIers to the name oI your base cIass as given in the extends decIaration oI your cIass. By doing this,
you avoid using the name oI your base cIass in more than one pIace. ShouId your inheritance tree change
during impIementation, the change is easiIy made by simpIy changing the extends decIaration oI your cIass.
<?php
class A {
function example() {
echo "I am A::example() and provide basic functionality.<br />\n";
}
}
class B extends A {
function example() {
echo "I am B::example() and provide additional functionality.<br />\n";
parent::example();
}
}
$b = new B;
// This will call B::example(), which will in turn call A::example().
$b->example();
?>
Serializing objects - objects in sessions
Note: In PHP 3, objects wiII Iose their cIass association throughout the process oI seriaIization and
unseriaIization. The resuIting variabIe is oI type object, but has no cIass and no methods, thus it is pretty
useIess (it has become just Iike an array with a Iunny syntax).
Caution
The IoIIowing inIormation is vaIid Ior PHP > 4 onIy.
seriaIize() returns a string containing a byte-stream representation oI any vaIue that can be stored in PHP.
unseriaIize() can use this string to recreate the originaI variabIe vaIues. Using seriaIize to save an object wiII
save aII variabIes in an object. The Iunctions in an object wiII not be saved, onIy the name oI the cIass.
In order to be abIe to unseriaIize() an object, the cIass oI that object needs to be deIined. That is, iI you have
an object Sa oI cIass Aon page1.php and seriaIize this, you'II get a string that reIers to cIass Aand contains aII
vaIues oI variabIed contained in Sa. II you want to be abIe to unseriaIize this on page2.php, recreating Sa oI
cIass A, the deIinition oI cIass Amust be present in page2.php. This can be done Ior exampIe by storing the
cIass deIinition oI cIass A in an incIude IiIe and incIuding this IiIe in both page1.php and page2.php.
<?php
// classa.inc:
class A {
var $one = 1;
function show_one() {
echo $this->one;
}
}
// page1.php:
include("classa.inc");
$a = new A;
$s = serialize($a);
// store $s somewhere where page2.php can find it.
$fp = fopen("store", "w");
fwrite($fp, $s);
fclose($fp);
// page2.php:
// this is needed for the unserialize to work properly.
include("classa.inc");
$s = implode("", @file("store"));
$a = unserialize($s);
// now use the function show_one() of the $a object.
$a->show_one();
?>
II you are using sessions and use sessionregister() to register objects, these objects are seriaIized
automaticaIIy at the end oI each PHP page, and are unseriaIized automaticaIIy on each oI the IoIIowing pages.
This basicaIIy means that these objects can show up on any oI your pages once they become part oI your
session.
It is strongIy recommended that you incIude the cIass deIinitions oI aII such registered objects on aII oI your
pages, even iI you do not actuaIIy use these cIasses on aII oI your pages. II you don't and an object is being
unseriaIized without its cIass deIinition being present, it wiII Iose its cIass association and become an object oI
cIass stdClass without any Iunctions avaiIabIe at aII, that is, it wiII become quite useIess.
So iI in the exampIe above Sa became part oI a session by running sessionregister("a"), you shouId incIude
the IiIe classa.inc on aII oI your pages, not onIy page1.php and page2.php.
The magic functions @@/$##' and @@269#='
seriaIize() checks iI your cIass has a Iunction with the magic name sleep. II so, that Iunction is being run
prior to any seriaIization. It can cIean up the object and is supposed to return an array with the names oI aII
variabIes oI that object that shouId be seriaIized. II the method doesn't return anything then NULL is seriaIized
and ENOTICE is issued.
The intended use oI sleep is to commit pending data or perIorm simiIar cIeanup tasks. AIso, the Iunction is
useIuI iI you have very Iarge objects which need not be saved compIeteIy.
ConverseIy, unseriaIize() checks Ior the presence oI a Iunction with the magic name wakeup. II present, this
Iunction can reconstruct any resources that object may have.
The intended use oI wakeup is to reestabIish any database connections that may have been Iost during
seriaIization and perIorm other reinitiaIization tasks.
References inside the constructor
Creating reIerences within the constructor can Iead to conIusing resuIts. This tutoriaI-Iike section heIps you to
avoid probIems.
<?php
class Foo {
function Foo($name) {
// create a reference inside the global array $globalref
global $globalref;
$globalref[] = &$this;
// set name to passed value
$this->setName($name);
// and put it out
$this->echoName();
}
function echoName() {
echo "<br />", $this->name;
}
function setName($name) {
$this->name = $name;
}
}
?>
Let us check out iI there is a diIIerence between Sbar1 which has been created using the copy operator and
Sbar2 which has been created using the reIerence & operator...
<?php
$bar1 = new Foo('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();
/* output:
set in constructor
set in constructor
set in constructor */
$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();
/* output:
set in constructor
set in constructor
set in constructor */
?>
ApparentIy there is no diIIerence, but in Iact there is a very signiIicant one: Sbar1 and Sglobalref[0{ are
NOT reIerenced, they are NOT the same variabIe. This is because "new" does not return a reIerence by
deIauIt, instead it returns a copy.
Note: There is no perIormance Ioss (since PHP 4 and up use reIerence counting) returning copies instead oI
reIerences. On the contrary it is most oIten better to simpIy work with copies instead oI reIerences, because
creating reIerences takes some time where creating copies virtuaIIy takes no time (unIess none oI them is a
Iarge array or object and one oI them gets changed and the other(s) one(s) subsequentIy, then it wouId be wise
to use reIerences to change them aII concurrentIy).
To prove what is written above Iet us watch the code beIow.
<?php
// now we will change the name. what do you expect?
// you could expect that both $bar1 and $globalref[0] change their names...
$bar1->setName('set from outside');
// as mentioned before this is not the case.
$bar1->echoName();
$globalref[0]->echoName();
/* output:
set from outside
set in constructor */
// let us see what is different with $bar2 and $globalref[1]
$bar2->setName('set from outside');
// luckily they are not only equal, they are the same variable
// thus $bar2->name and $globalref[1]->name are the same too
$bar2->echoName();
$globalref[1]->echoName();
/* output:
set from outside
set from outside */
?>
Another IinaI exampIe, try to understand it.
<?php
class A {
function A($i) {
$this->value = $i;
// try to figure out why we do not need a reference here
$this->b = new B($this);
}
function createRef() {
$this->c = new B($this);
}
function echoValue() {
echo "<br />","class ",get_class($this),': ',$this->value;
}
}
class B {
function B(&$a) {
$this->a = &$a;
}
function echoValue() {
echo "<br />","class ",get_class($this),': ',$this->a->value;
}
}
// try to understand why using a simple copy here would yield
// in an undesired result in the *-marked line
$a =& new A(10);
$a->createRef();
$a->echoValue();
$a->b->echoValue();
$a->c->echoValue();
$a->value = 11;
$a->echoValue();
$a->b->echoValue(); // *
$a->c->echoValue();
?>
The above exampIe wiII output:
class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11
Comparing objects
In PHP 4, objects are compared in a very simpIe manner, nameIy: Two object instances are equaI iI they have
the same attributes and vaIues, and are instances oI the same cIass. SimiIar ruIes are appIied when comparing
two objects using the identity operator ().
II we were to execute the code in the exampIe beIow:
Example 18.1. Example of object comparison in PHP 4
<?php
function bool2str($bool) {
if ($bool === false) {
return 'FALSE';
} else {
return 'TRUE';
}
}
function compareObjects(&$o1, &$o2) {
echo 'o1 == o2 : '.bool2str($o1 == $o2)."\n";
echo 'o1 != o2 : '.bool2str($o1 != $o2)."\n";
echo 'o1 === o2 : '.bool2str($o1 === $o2)."\n";
echo 'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
}
class Flag {
var $flag;
function Flag($flag=true) {
$this->flag = $flag;
}
}
class SwitchableFlag extends Flag {
function turnOn() {
$this->flag = true;
}
function turnOff() {
$this->flag = false;
}
}
$o = new Flag();
$p = new Flag(false);
$q = new Flag();
$r = new SwitchableFlag();
echo "Compare instances created with the same parameters\n";
compareObjects($o, $q);
echo "\nCompare instances created with different parameters\n";
compareObjects($o, $p);
echo "\nCompare an instance of a parent class with one from a subclass\n";
compareObjects($o, $r);
?>
The above exampIe wiII output:
Compare instances created with the same parameters
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE
Compare instances created with different parameters
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Compare an instance of a parent class with one from a subclass
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Which is the output we wiII expect to obtain given the comparison ruIes above. OnIy instances with the same
vaIues Ior their attributes and Irom the same cIass are considered equaI and identicaI.
Even in the cases where we have object composition, the same comparison ruIes appIy. In the exampIe beIow
we create a container cIass that stores an associative array oI Flag objects.
Example 18.2. Compound object comparisons in PHP 4
<?php
class FlagSet {
var $set;
function FlagSet($flagArr = array()) {
$this->set = $flagArr;
}
function addFlag($name, $flag) {
$this->set[$name] = $flag;
}
function removeFlag($name) {
if (array_key_exists($name, $this->set)) {
unset($this->set[$name]);
}
}
}
$u = new FlagSet();
$u->addFlag('flag1', $o);
$u->addFlag('flag2', $p);
$v = new FlagSet(array('flag1'=>$q, 'flag2'=>$p));
$w = new FlagSet(array('flag1'=>$q));
echo "\nComposite objects u(o,p) and v(q,p)\n";
compareObjects($u, $v);
echo "\nu(o,p) and w(q)\n";
compareObjects($u, $w);
?>
The above exampIe wiII output:
Composite objects u(o,p) and v(q,p)
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE
u(o,p) and w(q)
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Chapter 19. Classes and Objects (PHP 5)
Introduction
In PHP 5 there is a new Object ModeI. PHP's handIing oI objects has been compIeteIy rewritten, aIIowing Ior
better perIormance and more Ieatures.
Tip
You may aIso want to take a Iook at the Appendix T, Userland Naming Guide.
The Basics
class
Every cIass deIinition begins with the keyword cIass, IoIIowed by a cIass name, which can be any name that
isn't a reserved word in PHP. FoIIowed by a pair oI curIy braces, which contains the deIinition oI the cIasses
members and methods. Apseudo-variabIe, Sthis is avaiIabIe when a method is caIIed Irom within an object
context. Sthis is a reIerence to the caIIing object (usuaIIy the object to which the method beIongs, but can be
another object, iI the method is caIIed staticaIIy Irom the context oI a secondary object). This is iIIustrated in
the IoIIowing exampIes:
Example 19.1. (<"0/ variable in object-oriented language
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this is not defined.\n";
}
}
}
class B
{
function bar()
{
A::foo();
}
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
The above exampIe wiII output:
$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.
Example 19.2. Simple Class definition
<?php
class SimpleClass
{
// member declaration
public $var = 'a default value';
// method declaration
public function displayVar() {
echo $this->var;
}
}
?>
The deIauIt vaIue must be a constant expression, not (Ior exampIe) a variabIe, a cIass member or a Iunction
caII.
Example 19.3. Class members' default value
<?php
class SimpleClass
{
// invalid member declarations:
public $var1 = 'hello '.'world';
public $var2 = <<<EOD
hello world
EOD;
public $var3 = 1+2;
public $var4 = self::myStaticMethod();
public $var5 = $myVar;
// valid member declarations:
public $var6 = myConstant;
public $var7 = self::classConstant;
public $var8 = array(true, false);
}
?>
Note: There are some nice Iunctions to handIe cIasses and objects. You might want to take a Iook at the
CIass/Object Functions.
new
To create an instance oI a cIass, a new object must be created and assigned to a variabIe. An object wiII aIways
be assigned when creating a new object unIess the object has a constructor deIined that throws an exception
on error. CIasses shouId be deIined beIore instantiation (and in some cases this is a requirement).
Example 19.4. Creating an instance
<?php
$instance = new SimpleClass();
?>
In the cIass context, it is possibIe to create a new object by new self and new parent.
When assigning an aIready created instance oI a cIass to a new variabIe, the new variabIe wiII access the same
instance as the object that was assigned. This behaviour is the same when passing instances to a Iunction. A
copy oI an aIready created object can be made by cIoning it.
Example 19.5. Object Assignment
<?php
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
The above exampIe wiII output:
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}
extends
A cIass can inherit methods and members oI another cIass by using the extends keyword in the decIaration. It
is not possibIe to extend muItipIe cIasses, a cIass can onIy inherit one base cIass.
The inherited methods and members can be overridden, unIess the parent cIass has deIined a method as IinaI,
by redecIaring them with the same name deIined in the parent cIass. It is possibIe to access the overridden
methods or static members by reIerencing them with parent::
Example 19.6. Simple Class Inheritance
<?php
class ExtendClass extends SimpleClass
{
// Redefine the parent method
function displayVar()
{
echo "Extending class\n";
parent::displayVar();
}
}
$extended = new ExtendClass();
$extended->displayVar();
?>
The above exampIe wiII output:
Extending class
a default value
Autoloading Objects
Many deveIopers writing object-oriented appIications create one PHP source IiIe per-cIass deIinition. One oI
the biggest annoyances is having to write a Iong Iist oI needed incIudes at the beginning oI each script (one Ior
each cIass).
In PHP 5, this is no Ionger necessary. You may deIine an autoIoad Iunction which is automaticaIIy caIIed in
case you are trying to use a cIass which hasn't been deIined yet. By caIIing this Iunction the scripting engine is
given a Iast chance to Ioad the cIass beIore PHP IaiIs with an error.
Note: Exceptions thrown in autoIoad Iunction cannot be caught in the catch bIock and resuIts in a IataI
error.
Note: AutoIoading is not avaiIabIe iI using PHP in CLI interactive mode.
Note: II the cIass name is used e.g. in caIIuserIunc() then it can contain some dangerous characters such as
... It is recommended to not use the user-input in such Iunctions or at Ieast veriIy the input in __autoload().
Example 19.7. Autoload example
This exampIe attempts to Ioad the cIasses MvClass1 and MvClass2 Irom the IiIes MvClass1.php and
MvClass2.php respectiveIy.
<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
Constructors and Destructors
Constructor
void __construct ( |mixed $args |, $...|| )
PHP 5 aIIows deveIopers to decIare constructor methods Ior cIasses. CIasses which have a constructor method
caII this method on each newIy
Visibility
The visibiIity oI a property or method can be deIined by preIixing the decIaration with the keywords: pubIic,
protected or private. PubIic decIared items can be accessed everywhere. Protected Iimits access to inherited
and parent cIasses (and to the cIass that deIines the item). Private Iimits visibiIity onIy to the cIass that deIines
the item.
Members Visibility
CIass members must be deIined with pubIic, private, or protected.
Example 19.10. Member declaration
<?php
/**
* Define MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// We can redeclare the public and protected method, but not private
protected $protected = 'Protected2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj2 = new MyClass2();
echo $obj2->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello(); // Shows Public, Protected2, Undefined
?>
Note: The PHP 4 method oI decIaring a variabIe with the var keyword is stiII supported Ior compatibiIity
reasons (as a synonym Ior the pubIic keyword). In PHP 5 beIore 5.1.3, its usage wouId generate an E_STRICT
warning.
Method Visibility
CIass methods must be deIined with pubIic, private, or protected. Methods without any decIaration are deIined
as pubIic.
Example 19.11. Method Declaration
<?php
/**
* Define MyClass
*/
class MyClass
{
// Contructors must be public
public function __construct() { }
// Declare a public method
public function MyPublic() { }
// Declare a protected method
protected function MyProtected() { }
// Declare a private method
private function MyPrivate() { }
// This is public
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass;
$myclass->MyPublic(); // Works
$myclass->MyProtected(); // Fatal Error
$myclass->MyPrivate(); // Fatal Error
$myclass->Foo(); // Public, Protected and Private work
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// This is public
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // Fatal Error
}
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Works
$myclass2->Foo2(); // Public and Protected work, not Private
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic
?>
Scope Resolution Operator (::)
The Scope ResoIution Operator (aIso caIIed Paamayim Nekudotayim) or in simpIer terms, the doubIe coIon, is
a token that aIIows access to static, constant, and overridden members or methods oI a cIass.
When reIerencing these items Irom outside the cIass deIinition, use the name oI the cIass.
As oI PHP 5.3.0, it's possibIe to reIerence the cIass using a variabIe. Keywords Iike self, parent or static are
not aIIowed in dynamic cIass reIerences.
Paamayim Nekudotayim wouId, at Iirst, seem Iike a strange choice Ior naming a doubIe-coIon. However,
whiIe writing the Zend Engine 0.5 (which powers PHP 3), that's what the Zend team decided to caII it. It
actuaIIy does mean doubIe-coIon - in Hebrew!
Example 19.12. :: from outside the class definition
<?php
class MyClass {
const CONST_VALUE = 'A constant value';
}
$classname = 'MyClass';
echo $classname::CONST_VALUE;
echo MyClass::CONST_VALUE;
?>
Two speciaI keywords self and parent are used to access members or methods Irom inside the cIass deIinition.
Example 19.13. :: from inside the class definition
<?php
class OtherClass extends MyClass
{
public static $my_static = 'static var';
public static function doubleColon() {
echo parent::CONST_VALUE . "\n";
echo self::$my_static . "\n";
}
}
$classname = 'OtherClass';
echo $classname::doubleColon();
OtherClass::doubleColon();
?>
When an extending cIass overrides the parents deIinition oI a method, PHP wiII not caII the parent's method.
It's up to the extended cIass on whether or not the parent's method is caIIed. This aIso appIies to Constructors
and Destructors, OverIoading, and Magic method deIinitions.
Example 19.14. Calling a parent's method
<?php
class MyClass
{
protected function myFunc() {
echo "MyClass::myFunc()\n";
}
}
class OtherClass extends MyClass
{
// Override parent's definition
public function myFunc()
{
// But still call the parent function
parent::myFunc();
echo "OtherClass::myFunc()\n";
}
}
$class = new OtherClass();
$class->myFunc();
?>
Static Keyword
DecIaring cIass members or methods as static makes them accessibIe without needing an instantiation oI the
cIass. Amember decIared as static can not be accessed with an instantiated cIass object (though a static
method can).
For compatibiIity with PHP 4, iI no visibiIity decIaration is used, then the member or method wiII be treated
as iI it was decIared as public.
Because static methods are caIIabIe without an instance oI the object created, the pseudo variabIe Sthis is not
avaiIabIe inside the method decIared as static.
Static properties cannot be accessed through the object using the arrow operator ->.
CaIIing non-static methods staticaIIy generates an ESTRICT IeveI warning.
As oI PHP 5.3.0, it's possibIe to reIerence the cIass using a variabIe. Keywords Iike self, parent or static are
not aIIowed in dynamic cIass reIerences.
Example 19.15. Static member example
<?php
class Foo
{
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
}
class Bar extends Foo
{
public function fooStatic() {
return parent::$my_static;
}
}
print Foo::$my_static . "\n";
$foo = new Foo();
print $foo->staticValue() . "\n";
print $foo->my_static . "\n"; // Undefined "Property" my_static
print $foo::$my_static . "\n";
$classname = 'Foo';
print $classname::$my_static . "\n";
print Bar::$my_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>
Example 19.16. Static method example
<?php
class Foo {
public static function aStaticMethod() {
// ...
}
}
Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod();
?>
Class Constants
It is possibIe to deIine constant vaIues on a per-cIass basis remaining the same and unchangeabIe. Constants
diIIer Irom normaI variabIes in that you don't use the S symboI to decIare or use them.
The vaIue must be a constant expression, not (Ior exampIe) a variabIe, a cIass member, resuIt oI a
mathematicaI operation or a Iunction caII.
As oI PHP 5.3.0, it's possibIe to reIerence the cIass using a variabIe. Keywords Iike self, parent or static are
not aIIowed in dynamic cIass reIerences.
Example 19.17. Defining and using a constant
<?php
class MyClass
{
const constant = 'constant value';
function showConstant() {
echo self::constant . "\n";
}
}
echo MyClass::constant . "\n";
$classname = "MyClass";
echo $classname::constant . "\n";
$class = new MyClass();
$class->showConstant();
echo $class::constant."\n";
?>
Class Abstraction
PHP 5 introduces abstract cIasses and methods. It is not aIIowed to create an instance oI a cIass that has been
deIined as abstract. Any cIass that contains at Ieast one abstract method must aIso be abstract. Methods
deIined as abstract simpIy decIare the method's signature they cannot deIine the impIementation.
When inheriting Irom an abstract cIass, aII methods marked abstract in the parent's cIass decIaration must be
deIined by the chiId; additionaIIy, these methods must be deIined with the same (or a Iess restricted) visibiIity.
For exampIe, iI the abstract method is deIined as protected, the Iunction impIementation must be deIined as
either protected or pubIic, but not private.
Example 19.18. Abstract class example
<?php
abstract class AbstractClass
{
// Force Extending class to define this method
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// Common method
public function printOut() {
print $this->getValue() . "\n";
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue() {
return "ConcreteClass1";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue() {
return "ConcreteClass2";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass2";
}
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";
?>
The above exampIe wiII output:
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2
OId code that has no user-deIined cIasses or Iunctions named 'abstract' shouId run without modiIications.
Object Interfaces
Object interIaces aIIow you to create code which speciIies which methods a cIass must impIement, without
having to deIine how these methods are handIed.
InterIaces are deIined using the interIace keyword, in the same way as a standard cIass, but without any oI the
methods having their contents deIined.
AII methods decIared in an interIace must be pubIic, this is the nature oI an interIace.
implements
To impIement an interIace, the implements operator is used. AII methods in the interIace must be impIemented
within a cIass; IaiIure to do so wiII resuIt in a IataI error. CIasses may impIement more than one interIace iI
desired by separating each interIace with a comma.
Note: A cIass cannot impIement two interIaces that share Iunction names, since it wouId cause ambiguity.
Examples
Example 19.19. Interface example
<?php
// Declare the interface 'iTemplate'
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}
// Implement the interface
// This will work
class Template implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}
return $template;
}
}
// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
}
?>
Overloading
Both method caIIs and member accesses can be overIoaded via the caII, get and set methods. These
methods wiII onIy be triggered when your object or inherited object doesn't contain the member or method
you're trying to access. AII overIoading methods must not be deIined as static. AII overIoading methods must
be deIined as pubIic.
Since PHP 5.1.0 it is aIso possibIe to overIoad the isset() and unset() Iunctions via the isset and unset
methods respectiveIy. Method isset is caIIed aIso with empty().
Member overloading
void __set ( string $name, mixed $value )
mixed __get ( string $name )
bool __isset ( string $name )
void __unset ( string $name )
CIass members can be overIoaded to run custom code deIined in your cIass by deIining these speciaIIy named
methods. The Sname parameter used is the name oI the variabIe that shouId be set or retrieved. The set()
method's Svalue parameter speciIies the vaIue that the object shouId set the Sname.
Note: The set() method cannot take arguments by reIerence.
Example 19.20. overloading with __get, __set, __isset and __unset example
<?php
class Setter
{
public $n;
private $x = array("a" => 1, "b" => 2, "c" => 3);
public function __get($nm)
{
echo "Getting [$nm]\n";
if (isset($this->x[$nm])) {
$r = $this->x[$nm];
print "Returning: $r\n";
return $r;
} else {
echo "Nothing!\n";
}
}
public function __set($nm, $val)
{
echo "Setting [$nm] to $val\n";
if (isset($this->x[$nm])) {
$this->x[$nm] = $val;
echo "OK!\n";
} else {
echo "Not OK!\n";
}
}
public function __isset($nm)
{
echo "Checking if $nm is set\n";
return isset($this->x[$nm]);
}
public function __unset($nm)
{
echo "Unsetting $nm\n";
unset($this->x[$nm]);
}
}
$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump(isset($foo->a)); //true
unset($foo->a);
var_dump(isset($foo->a)); //false
// this doesn't pass through the __isset() method
// because 'n' is a public property
var_dump(isset($foo->n));
var_dump($foo);
?>
The above exampIe wiII output:
Setting [a] to 100
OK!
Getting [a]
Returning: 100
Setting [a] to 101
OK!
Getting [z]
Nothing!
Setting [z] to 1
Not OK!
Checking if a is set
bool(true)
Unsetting a
Checking if a is set
bool(false)
bool(true)
object(Setter)#1 (2) {
["n"]=>
int(1)
["x":"Setter":private]=>
array(2) {
["b"]=>
int(2)
["c"]=>
int(3)
}
}
Method overloading
mixed __call ( string $name, array $arguments )
The magic method caII() aIIows to capture invocation oI non existing methods. That way caII() can be
used to impIement user deIined method handIing that depends on the name oI the actuaI method being caIIed.
This is Ior instance useIuI Ior proxy impIementations. The arguments that were passed in the Iunction wiII be
deIined as an array in the Sarguments parameter. The vaIue returned Irom the caII() method wiII be returned
to the caIIer oI the method.
Example 19.21. overloading with __call example
<?php
class Caller
{
private $x = array(1, 2, 3);
public function __call($m, $a)
{
print "Method $m called:\n";
var_dump($a);
return $this->x;
}
}
$foo = new Caller();
$a = $foo->test(1, "2", 3.4, true);
var_dump($a);
?>
The above exampIe wiII output:
Method test called:
array(4) {
[0]=>
int(1)
[1]=>
string(1) "2"
[2]=>
float(3.4)
[3]=>
bool(true)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
Object Iteration
PHP 5 provides a way Ior objects to be deIined so it is possibIe to iterate through a Iist oI items, with, Ior
exampIe a Ioreach statement. By deIauIt, aII visibIe properties wiII be used Ior the iteration.
Example 19.22. Simple Object Iteration
<?php
class MyClass
{
public $var1 = 'value 1';
public $var2 = 'value 2';
public $var3 = 'value 3';
protected $protected = 'protected var';
private $private = 'private var';
function iterateVisible() {
echo "MyClass::iterateVisible:\n";
foreach($this as $key => $value) {
print "$key => $value\n";
}
}
}
$class = new MyClass();
foreach($class as $key => $value) {
print "$key => $value\n";
}
echo "\n";
$class->iterateVisible();
?>
The above exampIe wiII output:
var1 => value 1
var2 => value 2
var3 => value 3
MyClass::iterateVisible:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var
As the output shows, the Ioreach iterated through aII visibIe variabIes that can be accessed. To take it a step
Iurther you can implement one oI PHP 5's internaI interIace named Iterator. This aIIows the object to decide
what and how the object wiII be iterated.
Example 19.23. Object Iteration implementing Iterator
<?php
class MyIterator implements Iterator
{
private $var = array();
public function __construct($array)
{
if (is_array($array)) {
$this->var = $array;
}
}
public function rewind() {
echo "rewinding\n";
reset($this->var);
}
public function current() {
$var = current($this->var);
echo "current: $var\n";
return $var;
}
public function key() {
$var = key($this->var);
echo "key: $var\n";
return $var;
}
public function next() {
$var = next($this->var);
echo "next: $var\n";
return $var;
}
public function valid() {
$var = $this->current() !== false;
echo "valid: {$var}\n";
return $var;
}
}
$values = array(1,2,3);
$it = new MyIterator($values);
foreach ($it as $a => $b) {
print "$a: $b\n";
}
?>
The above exampIe wiII output:
rewinding
current: 1
valid: 1
current: 1
key: 0
0: 1
next: 2
current: 2
valid: 1
current: 2
key: 1
1: 2
next: 3
current: 3
valid: 1
current: 3
key: 2
2: 3
next:
current:
valid:
You can aIso deIine your cIass so that it doesn't have to deIine aII the Iterator Iunctions by simpIy
impIementing the PHP 5 IteratorAggregate interIace.
Example 19.24. Object Iteration implementing IteratorAggregate
<?php
class MyCollection implements IteratorAggregate
{
private $items = array();
private $count = 0;
// Required definition of interface IteratorAggregate
public function getIterator() {
return new MyIterator($this->items);
}
public function add($value) {
$this->items[$this->count++] = $value;
}
}
$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');
foreach ($coll as $key => $val) {
echo "key/value: [$key -> $val]\n\n";
}
?>
The above exampIe wiII output:
rewinding
current: value 1
valid: 1
current: value 1
key: 0
key/value: [0 -> value 1]
next: value 2
current: value 2
valid: 1
current: value 2
key: 1
key/value: [1 -> value 2]
next: value 3
current: value 3
valid: 1
current: value 3
key: 2
key/value: [2 -> value 3]
next:
current:
valid:
Note: For more exampIes oI iterators, see the SPL Extension.
Patterns
Patterns are ways to describe best practices and good designs. They show a IIexibIe soIution to common
programming probIems.
Factory
The Factory pattern aIIows Ior the instantiation oI objects at runtime. It is caIIed a Factory Pattern since it is
responsibIe Ior "manuIacturing" an object. A Parameterized Factory receives the name oI the cIass to
instantiate as argument.
Example 19.25. Parameterized Factory Method
<?php
class Example
{
// The parameterized factory method
public static function factory($type)
{
if (include_once 'Drivers/' . $type . '.php') {
$classname = 'Driver_' . $type;
return new $classname;
} else {
throw new Exception ('Driver not found');
}
}
}
?>
DeIining this method in a cIass aIIows drivers to be Ioaded on the IIy. II the Example cIass was a database
abstraction cIass, Ioading a MvSQL and SQLite driver couId be done as IoIIows:
<?php
// Load a MySQL Driver
$mysql = Example::factory('MySQL');
// Load a SQLite Driver
$sqlite = Example::factory('SQLite');
?>
Singleton
The SingIeton pattern appIies to situations in which there needs to be a singIe instance oI a cIass. The most
common exampIe oI this is a database connection. ImpIementing this pattern aIIows a programmer to make
this singIe instance easiIy accessibIe by many other objects.
Example 19.26. Singleton Function
<?php
class Example
{
// Hold an instance of the class
private static $instance;
// A private constructor; prevents direct creation of object
private function __construct()
{
echo 'I am constructed';
}
// The singleton method
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
// Example method
public function bark()
{
echo 'Woof!';
}
// Prevent users to clone the instance
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}
?>
This aIIows a singIe instance oI the Example cIass to be retrieved.
<?php
// This would fail because the constructor is private
$test = new Example;
// This will always retrieve a single instance of the class
$test = Example::singleton();
$test->bark();
// This will issue an E_USER_ERROR.
$test_clone = clone $test;
?>
Magic Methods
The Iunction names construct, destruct (see Constructors and Destructors), call, get, set, isset,
unset (see OverIoading), sleep, wakeup, toString, setstate and cIone are magicaI in PHP
cIasses. You cannot have Iunctions with these names in any oI your cIasses unIess you want the magic
IunctionaIity associated with them.
Caution
PHP reserves aII Iunction names starting with as magicaI. It is recommended that you do not use Iunction
names with in PHP unIess you want some documented magic IunctionaIity.
__sleep and __wakeup
seriaIize() checks iI your cIass has a Iunction with the magic name sleep. II so, that Iunction is executed
prior to any seriaIization. It can cIean up the object and is supposed to return an array with the names oI aII
variabIes oI that object that shouId be seriaIized. II the method doesn't return anything then NULL is seriaIized
and ENOTICE is issued.
The intended use oI sleep is to commit pending data or perIorm simiIar cIeanup tasks. AIso, the Iunction is
useIuI iI you have very Iarge objects which do not need to be saved compIeteIy.
ConverseIy, unseriaIize() checks Ior the presence oI a Iunction with the magic name wakeup. II present, this
Iunction can reconstruct any resources that the object may have.
The intended use oI wakeup is to reestabIish any database connections that may have been Iost during
seriaIization and perIorm other reinitiaIization tasks.
Example 19.27. Sleep and wakeup
<?php
class Connection {
protected $link;
private $server, $username, $password, $db;
public function __construct($server, $username, $password, $db)
{
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}
private function connect()
{
$this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
}
public function __sleep()
{
return array('server', 'username', 'password', 'db');
}
public function __wakeup()
{
$this->connect();
}
}
?>
__toString
The toString method aIIows a cIass to decide how it wiII react when it is converted to a string.
Example 19.28. Simple example
<?php
// Declare a simple class
class TestClass
{
public $foo;
public function __construct($foo) {
$this->foo = $foo;
}
public function __toString() {
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class;
?>
The above exampIe wiII output:
Hello
It is worth noting that beIore PHP 5.2.0 the toString method was onIy caIIed when it was directIy combined
with echo() or print(). Since PHP 5.2.0, it is caIIed in any string context (e.g. in printI() with s modiIier) but
not in other types contexts (e.g. with d modiIier). Since PHP 5.2.0, converting objects without toString
method to string wouId cause E_RECOVERABLE_ERROR.
__set_state
This static method is caIIed Ior cIasses exported by varexport() since PHP 5.1.0.
The onIy parameter oI this method is an array containing exported properties in the Iorm arrav(propertv
value. ...).
Final Keyword
PHP 5 introduces the IinaI keyword, which prevents chiId cIasses Irom overriding a method by preIixing the
deIinition with IinaI. II the cIass itseII is being deIined IinaI then it cannot be extended.
Example 19.29. Final methods example
<?php
class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}
final public function moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo "ChildClass::moreTesting() called\n";
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?>
Example 19.30. Final class example
<?php
final class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}
// Here it doesn't matter if you specify the function as final or not
final public function moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass {
}
// Results in Fatal error: Class ChildClass may not inherit from final class (BaseClass)
?>
Object cloning
Creating a copy oI an object with IuIIy repIicated properties is not aIways the wanted behavior. A good
exampIe oI the need Ior copy constructors, is iI you have an object which represents a GTK window and the
object hoIds the resource oI this GTK window, when you create a dupIicate you might want to create a new
window with the same properties and have the new object hoId the resource oI the new window. Another
exampIe is iI your object hoIds a reIerence to another object which it uses and when you repIicate the parent
object you want to create a new instance oI this other object so that the repIica has its own separate copy.
An object copy is created by using the cIone keyword (which caIIs the object's cIone() method iI possibIe).
An object's cIone() method cannot be caIIed directIy.
$copy_of_object = clone $object;
When an object is cIoned, PHP 5 wiII perIorm a shaIIow copy oI aII oI the object's properties. Any properties
that are reIerences to other variabIes, wiII remain reIerences. II a cIone() method is deIined, then the newIy
created object's cIone() method wiII be caIIed, to aIIow any necessary properties that need to be changed.
Example 19.31. Cloning an object
<?php
class SubObject
{
static $instances = 0;
public $instance;
public function __construct() {
$this->instance = ++self::$instances;
}
public function __clone() {
$this->instance = ++self::$instances;
}
}
class MyCloneable
{
public $object1;
public $object2;
function __clone()
{
// Force a copy of this->object, otherwise
// it will point to same object.
$this->object1 = clone $this->object1;
}
}
$obj = new MyCloneable();
$obj->object1 = new SubObject();
$obj->object2 = new SubObject();
$obj2 = clone $obj;
print("Original Object:\n");
print_r($obj);
print("Cloned Object:\n");
print_r($obj2);
?>
The above exampIe wiII output:
Original Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)
[object2] => SubObject Object
(
[instance] => 2
)
)
Cloned Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)
[object2] => SubObject Object
(
[instance] => 2
)
)
Comparing objects
In PHP 5, object comparison is more compIicated than in PHP 4 and more in accordance to what one wiII
expect Irom an Object Oriented Language (not that PHP 5 is such a Ianguage).
When using the comparison operator (), object variabIes are compared in a simpIe manner, nameIy: Two
object instances are equaI iI they have the same attributes and vaIues, and are instances oI the same cIass.
On the other hand, when using the identity operator (), object variabIes are identicaI iI and onIy iI they
reIer to the same instance oI the same cIass.
An exampIe wiII cIariIy these ruIes.
Example 19.32. Example of object comparison in PHP 5
<?php
function bool2str($bool)
{
if ($bool === false) {
return 'FALSE';
} else {
return 'TRUE';
}
}
function compareObjects(&$o1, &$o2)
{
echo 'o1 == o2 : ' . bool2str($o1 == $o2) . "\n";
echo 'o1 != o2 : ' . bool2str($o1 != $o2) . "\n";
echo 'o1 === o2 : ' . bool2str($o1 === $o2) . "\n";
echo 'o1 !== o2 : ' . bool2str($o1 !== $o2) . "\n";
}
class Flag
{
public $flag;
function Flag($flag = true) {
$this->flag = $flag;
}
}
class OtherFlag
{
public $flag;
function OtherFlag($flag = true) {
$this->flag = $flag;
}
}
$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();
echo "Two instances of the same class\n";
compareObjects($o, $p);
echo "\nTwo references to the same instance\n";
compareObjects($o, $q);
echo "\nInstances of two different classes\n";
compareObjects($o, $r);
?>
The above exampIe wiII output:
Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Two references to the same instance
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE
Instances of two different classes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Note: Extensions can deIine own ruIes Ior their objects comparison.
Reflection
Introduction
PHP 5 comes with a compIete reIIection API that adds the abiIity to reverse-engineer cIasses, interIaces,
Iunctions and methods as weII as extensions. AdditionaIIy, the reIIection API aIso oIIers ways oI retrieving
doc comments Ior Iunctions, cIasses and methods.
The reIIection API is an object-oriented extension to the Zend Engine, consisting oI the IoIIowing cIasses:
<?php
class Reflection { }
interface Reflector { }
class ReflectionException extends Exception { }
class ReflectionFunction extends ReflectionFunctionAbstract implements Reflector { }
class ReflectionParameter implements Reflector { }
class ReflectionMethod extends ReflectionFunctionAbstract implements Reflector { }
class ReflectionClass implements Reflector { }
class ReflectionObject extends ReflectionClass { }
class ReflectionProperty implements Reflector { }
class ReflectionExtension implements Reflector { }
?>
Note: For detaiIs on these cIasses, have a Iook at the next chapters.
II we were to execute the code in the exampIe beIow:
Example 19.33. Basic usage of the reflection API
<?php
Reflection::export(new ReflectionClass('Exception'));
?>
The above exampIe wiII output:
Class [ <internal> class Exception ] {
- Constants [0] {
}
- Static properties [0] {
}
- Static methods [0] {
}
- Properties [6] {
Property [ <default> protected $message ]
Property [ <default> private $string ]
Property [ <default> protected $code ]
Property [ <default> protected $file ]
Property [ <default> protected $line ]
Property [ <default> private $trace ]
}
- Methods [9] {
Method [ <internal> final private method __clone ] {
}
Method [ <internal, ctor> public method __construct ] {
- Parameters [2] {
Parameter #0 [ <optional> $message ]
Parameter #1 [ <optional> $code ]
}
}
Method [ <internal> final public method getMessage ] {
}
Method [ <internal> final public method getCode ] {
}
Method [ <internal> final public method getFile ] {
}
Method [ <internal> final public method getLine ] {
}
Method [ <internal> final public method getTrace ] {
}
Method [ <internal> final public method getTraceAsString ] {
}
Method [ <internal> public method __toString ] {
}
}
}
"#$%#&'()
Reflector is an interIace impIemented by aII exportabIe ReIIection cIasses.
<?php
interface Reflector
{
public string __toString()
public static string export()
}
?>
"#$%#&'*(+,-&#.'*(+
ReflectionException extends the standard Exception and is thrown by ReIIection API. No speciIic methods
or properties are introduced.
"#$%#&'*(+/0+&'*(+
The ReflectionFunction cIass Iets you reverse-engineer Iunctions.
<?php
class ReflectionFunction extends ReflectionFunctionAbstract implements Reflector
{
final private __clone()
public void __construct(string name)
public string __toString()
public static string export(string name, bool return)
public string getName()
public bool isInternal()
public bool isDisabled()
public bool isUserDefined()
public string getFileName()
public int getStartLine()
public int getEndLine()
public string getDocComment()
public array getStaticVariables()
public mixed invoke([mixed args [, ...]])
public mixed invokeArgs(array args)
public bool returnsReference()
public ReflectionParameter[] getParameters()
public int getNumberOfParameters()
public int getNumberOfRequiredParameters()
}
?>
Parent cIass ReflectionFunctionAbstract has the same methods except invoke(), invokeArgs(), export()
and isDisabled().
Note: getNumberOfParameters() and getNumberOfRequiredParameters() were added in PHP 5.0.3,
whiIe invokeArgs() was added in PHP 5.1.0.
To introspect a Iunction, you wiII Iirst have to create an instance oI the ReflectionFunction cIass. You can
then caII any oI the above methods on this instance.
Example 19.34. Using the ReflectionFunction class
<?php
/**
* A simple counter
*
* @return int
*/
function counter()
{
static $c = 0;
return $c++;
}
// Create an instance of the ReflectionFunction class
$func = new ReflectionFunction('counter');
// Print out basic information
printf(
"===> The %s function '%s'\n".
" declared in %s\n".
" lines %d to %d\n",
$func->isInternal() ? 'internal' : 'user-defined',
$func->getName(),
$func->getFileName(),
$func->getStartLine(),
$func->getEndline()
);
// Print documentation comment
printf("---> Documentation:\n %s\n", var_export($func->getDocComment(), 1));
// Print static variables if existant
if ($statics = $func->getStaticVariables())
{
printf("---> Static variables: %s\n", var_export($statics, 1));
}
// Invoke the function
printf("---> Invokation results in: ");
var_dump($func->invoke());
// you may prefer to use the export() method
echo "\nReflectionFunction::export() results:\n";
echo ReflectionFunction::export('counter');
?>
Note: The method invoke() accepts a variabIe number oI arguments which are passed to the Iunction just as in
caIIuserIunc().
"#$%#&'*(+12)23#'#)
The ReflectionParameter cIass retrieves inIormation about a Iunction's or method's parameters.
<?php
class ReflectionParameter implements Reflector
{
final private __clone()
public void __construct(string function, string parameter)
public string __toString()
public static string export(mixed function, mixed parameter, bool return)
public string getName()
public bool isPassedByReference()
public ReflectionClass getDeclaringClass()
public ReflectionClass getClass()
public bool isArray()
public bool allowsNull()
public bool isPassedByReference()
public bool isOptional()
public bool isDefaultValueAvailable()
public mixed getDefaultValue()
}
?>
Note: getDefaultValue(), isDefaultValueAvailable() and isOptional() were added in PHP 5.0.3, whiIe
isArray() was added in PHP 5.1.0. getDeclaringFunction() and getPosition() were added in PHP 5.2.3.
To introspect Iunction parameters, you wiII Iirst have to create an instance oI the ReflectionFunction or
ReflectionMethod cIasses and then use their getParameters() method to retrieve an array oI parameters.
Example 19.35. Using the ReflectionParameter class
<?php
function foo($a, $b, $c) { }
function bar(Exception $a, &$b, $c) { }
function baz(ReflectionFunction $a, $b = 1, $c = null) { }
function abc() { }
// Create an instance of ReflectionFunction with the
// parameter given from the command line.
$reflect = new ReflectionFunction($argv[1]);
echo $reflect;
foreach ($reflect->getParameters() as $i => $param) {
printf(
"-- Parameter #%d: %s {\n".
" Class: %s\n".
" Allows NULL: %s\n".
" Passed to by reference: %s\n".
" Is optional?: %s\n".
"}\n",
$i,
$param->getName(),
var_export($param->getClass(), 1),
var_export($param->allowsNull(), 1),
var_export($param->isPassedByReference(), 1),
$param->isOptional() ? 'yes' : 'no'
);
}
?>
"#$%#&'*(+4%255
The ReflectionClass cIass Iets you reverse-engineer cIasses and interIaces.
<?php
class ReflectionClass implements Reflector
{
final private __clone()
public void __construct(string name)
public string __toString()
public static string export(mixed class, bool return)
public string getName()
public bool isInternal()
public bool isUserDefined()
public bool isInstantiable()
public bool hasConstant(string name)
public bool hasMethod(string name)
public bool hasProperty(string name)
public string getFileName()
public int getStartLine()
public int getEndLine()
public string getDocComment()
public ReflectionMethod getConstructor()
public ReflectionMethod getMethod(string name)
public ReflectionMethod[] getMethods()
public ReflectionProperty getProperty(string name)
public ReflectionProperty[] getProperties()
public array getConstants()
public mixed getConstant(string name)
public ReflectionClass[] getInterfaces()
public bool isInterface()
public bool isAbstract()
public bool isFinal()
public int getModifiers()
public bool isInstance(stdclass object)
public stdclass newInstance(mixed args)
public stdclass newInstanceArgs(array args)
public ReflectionClass getParentClass()
public bool isSubclassOf(ReflectionClass class)
public array getStaticProperties()
public mixed getStaticPropertyValue(string name [, mixed default])
public void setStaticPropertyValue(string name, mixed value)
public array getDefaultProperties()
public bool isIterateable()
public bool implementsInterface(string name)
public ReflectionExtension getExtension()
public string getExtensionName()
}
?>
Note: hasConstant(), hasMethod(), hasProperty(), getStaticPropertyValue() and
setStaticPropertyValue() were added in PHP 5.1.0, whiIe newInstanceArgs() was added in PHP 5.1.3.
To introspect a cIass, you wiII Iirst have to create an instance oI the ReflectionClass cIass. You can then caII
any oI the above methods on this instance.
Example 19.36. Using the ReflectionClass class
<?php
interface Serializable
{
// ...
}
class Object
{
// ...
}
/**
* A counter class
*/
class Counter extends Object implements Serializable
{
const START = 0;
private static $c = Counter::START;
/**
* Invoke counter
*
* @access public
* @return int
*/
public function count() {
return self::$c++;
}
}
// Create an instance of the ReflectionClass class
$class = new ReflectionClass('Counter');
// Print out basic information
printf(
"===> The %s%s%s %s '%s' [extends %s]\n" .
" declared in %s\n" .
" lines %d to %d\n" .
" having the modifiers %d [%s]\n",
$class->isInternal() ? 'internal' : 'user-defined',
$class->isAbstract() ? ' abstract' : '',
$class->isFinal() ? ' final' : '',
$class->isInterface() ? 'interface' : 'class',
$class->getName(),
var_export($class->getParentClass(), 1),
$class->getFileName(),
$class->getStartLine(),
$class->getEndline(),
$class->getModifiers(),
implode(' ', Reflection::getModifierNames($class->getModifiers()))
);
// Print documentation comment
printf("---> Documentation:\n %s\n", var_export($class->getDocComment(), 1));
// Print which interfaces are implemented by this class
printf("---> Implements:\n %s\n", var_export($class->getInterfaces(), 1));
// Print class constants
printf("---> Constants: %s\n", var_export($class->getConstants(), 1));
// Print class properties
printf("---> Properties: %s\n", var_export($class->getProperties(), 1));
// Print class methods
printf("---> Methods: %s\n", var_export($class->getMethods(), 1));
// If this class is instantiable, create an instance
if ($class->isInstantiable()) {
$counter = $class->newInstance();
echo '---> $counter is instance? ';
echo $class->isInstance($counter) ? 'yes' : 'no';
echo "\n---> new Object() is instance? ";
echo $class->isInstance(new Object()) ? 'yes' : 'no';
}
?>
Note: The method newInstance() accepts a variabIe number oI arguments which are passed to the Iunction
just as in caIIuserIunc().
Note: Sclass new ReflectionClass(Foo), Sclass-isInstance(Sarg) is equivaIent to Sarg instanceof Foo or
isa(Sarg. Foo).
"#$%#&'*(+678#&'
The ReflectionObject cIass Iets you reverse-engineer objects.
<?php
class ReflectionObject extends ReflectionClass
{
final private __clone()
public void __construct(mixed object)
public string __toString()
public static string export(mixed object, bool return)
}
?>
"#$%#&'*(+9#';(<
The ReflectionMethod cIass Iets you reverse-engineer cIass methods.
<?php
class ReflectionMethod extends ReflectionFunctionAbstract implements Reflector
{
public void __construct(mixed class, string name)
public string __toString()
public static string export(mixed class, string name, bool return)
public mixed invoke(stdclass object [, mixed args [, ...]])
public mixed invokeArgs(stdclass object, array args)
public bool isFinal()
public bool isAbstract()
public bool isPublic()
public bool isPrivate()
public bool isProtected()
public bool isStatic()
public bool isConstructor()
public bool isDestructor()
public int getModifiers()
public ReflectionClass getDeclaringClass()
// Inherited from ReflectionFunctionAbstract
final private __clone()
public string getName()
public bool isInternal()
public bool isUserDefined()
public string getFileName()
public int getStartLine()
public int getEndLine()
public string getDocComment()
public array getStaticVariables()
public bool returnsReference()
public ReflectionParameter[] getParameters()
public int getNumberOfParameters()
public int getNumberOfRequiredParameters()
}
?>
To introspect a method, you wiII Iirst have to create an instance oI the ReflectionMethod cIass. You can then
caII any oI the above methods on this instance.
Example 19.37. Using the ReflectionMethod class
<?php
class Counter
{
private static $c = 0;
/**
* Increment counter
*
* @final
* @static
* @access public
* @return int
*/
final public static function increment()
{
return ++self::$c;
}
}
// Create an instance of the ReflectionMethod class
$method = new ReflectionMethod('Counter', 'increment');
// Print out basic information
printf(
"===> The %s%s%s%s%s%s%s method '%s' (which is %s)\n" .
" declared in %s\n" .
" lines %d to %d\n" .
" having the modifiers %d[%s]\n",
$method->isInternal() ? 'internal' : 'user-defined',
$method->isAbstract() ? ' abstract' : '',
$method->isFinal() ? ' final' : '',
$method->isPublic() ? ' public' : '',
$method->isPrivate() ? ' private' : '',
$method->isProtected() ? ' protected' : '',
$method->isStatic() ? ' static' : '',
$method->getName(),
$method->isConstructor() ? 'the constructor' : 'a regular method',
$method->getFileName(),
$method->getStartLine(),
$method->getEndline(),
$method->getModifiers(),
implode(' ', Reflection::getModifierNames($method->getModifiers()))
);
// Print documentation comment
printf("---> Documentation:\n %s\n", var_export($method->getDocComment(), 1));
// Print static variables if existant
if ($statics= $method->getStaticVariables()) {
printf("---> Static variables: %s\n", var_export($statics, 1));
}
// Invoke the method
printf("---> Invokation results in: ");
var_dump($method->invoke(NULL));
?>
Note: Trying to invoke private, protected or abstract methods wiII resuIt in an exception being thrown Irom
the invoke() method.
Note: For static methods as seen above, you shouId pass NULL as the Iirst argument to invoke(). For non-
static methods, pass an instance oI the cIass.
"#$%#&'*(+1)(.#)'=
The ReflectionProperty cIass Iets you reverse-engineer cIass properties.
<?php
class ReflectionProperty implements Reflector
{
final private __clone()
public void __construct(mixed class, string name)
public string __toString()
public static string export(mixed class, string name, bool return)
public string getName()
public bool isPublic()
public bool isPrivate()
public bool isProtected()
public bool isStatic()
public bool isDefault()
public int getModifiers()
public mixed getValue(stdclass object)
public void setValue(stdclass object, mixed value)
public ReflectionClass getDeclaringClass()
public string getDocComment()
}
?>
Note: getDocComment() was added in PHP 5.1.0.
To introspect a property, you wiII Iirst have to create an instance oI the ReflectionProperty cIass. You can
then caII any oI the above methods on this instance.
Example 19.38. Using the ReflectionProperty class
<?php
class String
{
public $length = 5;
}
// Create an instance of the ReflectionProperty class
$prop = new ReflectionProperty('String', 'length');
// Print out basic information
printf(
"===> The%s%s%s%s property '%s' (which was %s)\n" .
" having the modifiers %s\n",
$prop->isPublic() ? ' public' : '',
$prop->isPrivate() ? ' private' : '',
$prop->isProtected() ? ' protected' : '',
$prop->isStatic() ? ' static' : '',
$prop->getName(),
$prop->isDefault() ? 'declared at compile-time' : 'created at run-time',
var_export(Reflection::getModifierNames($prop->getModifiers()), 1)
);
// Create an instance of String
$obj= new String();
// Get current value
printf("---> Value is: ");
var_dump($prop->getValue($obj));
// Change value
$prop->setValue($obj, 10);
printf("---> Setting value to 10, new value is: ");
var_dump($prop->getValue($obj));
// Dump object
var_dump($obj);
?>
Note: Trying to get or set private or protected cIass property's vaIues wiII resuIt in an exception being thrown.
"#$%#&'*(+,-'#+5*(+
The ReflectionExtension cIass Iets you reverse-engineer extensions. You can retrieve aII Ioaded extensions
at runtime using the getIoadedextensions().
<?php
class ReflectionExtension implements Reflector {
final private __clone()
public void __construct(string name)
public string __toString()
public static string export(string name, bool return)
public string getName()
public string getVersion()
public ReflectionFunction[] getFunctions()
public array getConstants()
public array getINIEntries()
public ReflectionClass[] getClasses()
public array getClassNames()
public string info()
}
?>
To introspect an extension, you wiII Iirst have to create an instance oI the ReflectionExtension cIass. You
can then caII any oI the above methods on this instance.
Example 19.39. Using the ReflectionExtension class
<?php
// Create an instance of the ReflectionProperty class
$ext = new ReflectionExtension('standard');
// Print out basic information
printf(
"Name : %s\n" .
"Version : %s\n" .
"Functions : [%d] %s\n" .
"Constants : [%d] %s\n" .
"INI entries : [%d] %s\n" .
"Classes : [%d] %s\n",
$ext->getName(),
$ext->getVersion() ? $ext->getVersion() : 'NO_VERSION',
sizeof($ext->getFunctions()),
var_export($ext->getFunctions(), 1),
sizeof($ext->getConstants()),
var_export($ext->getConstants(), 1),
sizeof($ext->getINIEntries()),
var_export($ext->getINIEntries(), 1),
sizeof($ext->getClassNames()),
var_export($ext->getClassNames(), 1)
);
?>
Extending the reflection classes
In case you want to create speciaIized versions oI the buiIt-in cIasses (say, Ior creating coIorized HTML when
being exported, having easy-access member variabIes instead oI methods or having utiIity methods), you may
go ahead and extend them.
Example 19.40. Extending the built-in classes
<?php
/**
* My Reflection_Method class
*/
class My_Reflection_Method extends ReflectionMethod
{
public $visibility = array();
public function __construct($o, $m)
{
parent::__construct($o, $m);
$this->visibility = Reflection::getModifierNames($this->getModifiers());
}
}
/**
* Demo class #1
*
*/
class T {
protected function x() {}
}
/**
* Demo class #2
*
*/
class U extends T {
function x() {}
}
// Print out information
var_dump(new My_Reflection_Method('U', 'x'));
?>
Note: Caution: II you're overwriting the constructor, remember to caII the parent's constructor beIore any
code you insert. FaiIing to do so wiII resuIt in the IoIIowing: Fatal error. Internal error. Failed to retrieve the
reflection obfect
Type Hinting
PHP 5 introduces Type Hinting. Functions are now abIe to Iorce parameters to be objects (by speciIying the
name oI the cIass in the Iunction prototype) or arrays (since PHP 5.1).
Example 19.41. Type Hinting examples
<?php
// An example class
class MyClass
{
/**
* A test function
*
* First parameter must be an object of type OtherClass
*/
public function test(OtherClass $otherclass) {
echo $otherclass->var;
}
/**
* Another test function
*
* First parameter must be an array
*/
public function test_array(array $input_array) {
print_r($input_array);
}
}
// Another example class
class OtherClass {
public $var = 'Hello World';
}
?>
FaiIing to satisIy the type hint resuIts in a catchabIe IataI error.
<?php
// An instance of each class
$myclass = new MyClass;
$otherclass = new OtherClass;
// Fatal Error: Argument 1 must be an object of class OtherClass
$myclass->test('hello');
// Fatal Error: Argument 1 must be an instance of OtherClass
$foo = new stdClass;
$myclass->test($foo);
// Fatal Error: Argument 1 must not be null
$myclass->test(null);
// Works: Prints Hello World
$myclass->test($otherclass);
// Fatal Error: Argument 1 must be an array
$myclass->test_array('a string');
// Works: Prints the array
$myclass->test_array(array('a', 'b', 'c'));
?>
Type hinting aIso works with Iunctions:
<?php
// An example class
class MyClass {
public $var = 'Hello World';
}
/**
* A test function
*
* First parameter must be an object of type MyClass
*/
function MyFunction (MyClass $foo) {
echo $foo->var;
}
// Works
$myclass = new MyClass;
MyFunction($myclass);
?>
Type Hints can onIy be oI the object and array (since PHP 5.1) type. TraditionaI type hinting with int and
string isn't supported.
Chapter 21. Exceptions
PHP 5 has an exception modeI simiIar to that oI other programming Ianguages. An exception can be thrown,
and caught ("catched") within PHP. Code may be surrounded in a trv bIock, to IaciIitate the catching oI
potentiaI exceptions. Each trv must have at Ieast one corresponding catch bIock. MuItipIe catch bIocks can be
used to catch diIIerent cIasses oI exeptions. NormaI execution (when no exception is thrown within the trv
bIock, or when a catch matching the thrown exception's cIass is not present) wiII continue aIter that Iast catch
bIock deIined in sequence. Exceptions can be thrown (or re-thrown) within a catch bIock.
When an exception is thrown, code IoIIowing the statement wiII not be executed, and PHP wiII attempt to Iind
the Iirst matching catch bIock. II an exception is not caught, a PHP FataI Error wiII be issued with an
"Uncaught Exception ..." message, unIess a handIer has been deIined with setexceptionhandIer().
Example 21.1. Throwing an Exception
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
else return 1/$x;
}
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
// Continue execution
echo 'Hello World';
?>
The above exampIe wiII output:
0.2
Caught exception: Division by zero.
Hello World
Extending Exceptions
A User deIined Exception cIass can be deIined by extending the buiIt-in Exception cIass. The members and
properties beIow, show what is accessibIe within the chiId cIass that derives Irom the buiIt-in Exception cIass.
Example 21.2. The Built in Exception class
<?php
class Exception
{
protected $message = 'Unknown exception'; // exception message
protected $code = 0; // user defined exception code
protected $file; // source filename of exception
protected $line; // source line of exception
function __construct($message = null, $code = 0);
final function getMessage(); // message of exception
final function getCode(); // code of exception
final function getFile(); // source filename
final function getLine(); // source line
final function getTrace(); // an array of the backtrace()
final function getTraceAsString(); // formated string of trace
/* Overrideable */
function __toString(); // formated string for display
}
?>
II a cIass extends the buiIt-in Exception cIass and re-deIines the constructor, it is highIy recomended that it
aIso caII parent::construct() to ensure aII avaiIabIe data has been properIy assigned. The toString()
method can be overriden to provide a custom output when the object is presented as a string.
Example 21.3. Extending the Exception class
<?php
/**
* Define a custom exception class
*/
class MyException extends Exception
{
// Redefine the exception so message isn't optional
public function __construct($message, $code = 0) {
// some code
// make sure everything is assigned properly
parent::__construct($message, $code);
}
// custom string representation of object
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "A Custom function for this type of exception\n";
}
}
/**
* Create a class to test the exception
*/
class TestException
{
public $var;
const THROW_NONE = 0;
const THROW_CUSTOM = 1;
const THROW_DEFAULT = 2;
function __construct($avalue = self::THROW_NONE) {
switch ($avalue) {
case self::THROW_CUSTOM:
// throw custom exception
throw new MyException('1 is an invalid parameter', 5);
break;
case self::THROW_DEFAULT:
// throw default one.
throw new Exception('2 isnt allowed as a parameter', 6);
break;
default:
// No exception, object will be created.
$this->var = $avalue;
break;
}
}
}
// Example 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) { // Will be caught
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) { // Skipped
echo "Caught Default Exception\n", $e;
}
// Continue execution
var_dump($o);
echo "\n\n";
// Example 2
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) { // Doesn't match this type
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) { // Will be caught
echo "Caught Default Exception\n", $e;
}
// Continue execution
var_dump($o);
echo "\n\n";
// Example 3
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (Exception $e) { // Will be caught
echo "Default Exception caught\n", $e;
}
// Continue execution
var_dump($o);
echo "\n\n";
// Example 4
try {
$o = new TestException();
} catch (Exception $e) { // Skipped, no exception
echo "Default Exception caught\n", $e;
}
// Continue execution
var_dump($o);
echo "\n\n";
?>
Chapter 22. References Explained
What References Are
ReIerences in PHP are a means to access the same variabIe content by diIIerent names. They are not Iike C
pointers; instead, they are symboI tabIe aIiases. Note that in PHP, variabIe name and variabIe content are
diIIerent, so the same content can have diIIerent names. The most cIose anaIogy is with Unix IiIenames and
IiIes - variabIe names are directory entries, whiIe variabIe contents is the IiIe itseII. ReIerences can be thought
oI as hardIinking in Unix IiIesystem.
What References Do
PHP reIerences aIIow you to make two variabIes to reIer to the same content. Meaning, when you do:
<?php
$a =& $b;
?>
it means that Sa and Sb point to the same content.
Note: Sa and Sb are compIeteIy equaI here, that's not Sa is pointing to Sb or vice versa, that's Sa and Sb
pointing to the same pIace.
Note: II array with reIerences is copied, its vaIues are not dereIerenced. This is vaIid aIso Ior arrays passed by
vaIue to Iunctions.
Note: II you assign, pass or return an undeIined variabIe by reIerence, it wiII get created.
Example 22.1. Using references with undefined variables
<?php
function foo(&$var) { }
foo($a); // $a is "created" and assigned to null
$b = array();
foo($b['b']);
var_dump(array_key_exists('b', $b)); // bool(true)
$c = new StdClass;
foo($c->d);
var_dump(property_exists($c, 'd')); // bool(true)
?>
The same syntax can be used with Iunctions, that return reIerences, and with new operator (in PHP 4.0.4 and
Iater):
<?php
$bar =& new fooclass();
$foo =& find_var($bar);
?>
Since PHP 5, new return reIerence automaticaIIy so using & in this context is deprecated and produces
ESTRICT IeveI message.
Note: Not using the & operator causes a copy oI the object to be made. II you use Sthis in the cIass it wiII
operate on the current instance oI the cIass. The assignment without & wiII copy the instance (i.e. the object)
and Sthis wiII operate on the copy, which is not aIways what is desired. UsuaIIy you want to have a singIe
instance to work with, due to perIormance and memory consumption issues.
WhiIe you can use the operator to mute any errors in the constructor when using it as new, this does not
work when using the &new statement. This is a Iimitation oI the Zend Engine and wiII thereIore resuIt in a
parser error.
Warning
II you assign a reIerence to a variabIe decIared global inside a Iunction, the reIerence wiII be visibIe onIy
inside the Iunction. You can avoid this by using the SGLOBALS array.
Example 22.2. Referencing global variables inside function
<?php
$var1 = "Example variable";
$var2 = "";
function global_references($use_globals)
{
global $var1, $var2;
if (!$use_globals) {
$var2 =& $var1; // visible only inside the function
} else {
$GLOBALS["var2"] =& $var1; // visible also in global context
}
}
global_references(false);
echo "var2 is set to '$var2'\n"; // var2 is set to ''
global_references(true);
echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable'
?>
Think about global Svar, as a shortcut to Svar & SGLOBALS[var{,. Thus assigning other reIerence to Svar
onIy changes the IocaI variabIe's reIerence.
Note: II you assign a vaIue to a variabIe with reIerences in a Ioreach statement, the reIerences are modiIied
too.
Example 22.3. References and foreach statement
<?php
$ref = 0;
$row =& $ref;
foreach (array(1, 2, 3) as $row) {
// do something
}
echo $ref; // 3 - last element of the iterated array
?>
The second thing reIerences do is to pass variabIes by-reIerence. This is done by making a IocaI variabIe in a
Iunction and a variabIe in the caIIing scope reIerence to the same content. ExampIe:
<?php
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
?>
wiII make Sa to be 6. This happens because in the Iunction foo the variabIe Svar reIers to the same content as
Sa. See aIso more detaiIed expIanations about passing by reIerence.
The third thing reIerence can do is return by reIerence.
What References Are Not
As said beIore, reIerences aren't pointers. That means, the IoIIowing construct won't do what you expect:
<?php
function foo(&$var)
{
$var =& $GLOBALS["baz"];
}
foo($bar);
?>
What happens is that Svar in foo wiII be bound with Sbar in caIIer, but then it wiII be re-bound with
SGLOBALS["ba:"{. There's no way to bind Sbar in the caIIing scope to something eIse using the reIerence
mechanism, since Sbar is not avaiIabIe in the Iunction foo (it is represented by Svar, but Svar has onIy
variabIe contents and not name-to-vaIue binding in the caIIing symboI tabIe). You can use returning reIerences
to reIerence variabIes seIected by the Iunction.
Passing by Reference
You can pass variabIe to Iunction by reIerence, so that Iunction couId modiIy its arguments. The syntax is as
IoIIows:
<?php
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
// $a is 6 here
?>
Note that there's no reIerence sign on Iunction caII - onIy on Iunction deIinition. Function deIinition aIone is
enough to correctIy pass the argument by reIerence. In recent versions oI PHP you wiII get a warning saying
that "CaII-time pass-by-reIerence" is deprecated when you use a & in foo(&Sa),.
The IoIIowing things can be passed by reIerence:
VariabIe, i.e. foo(Sa)
New statement, i.e. foo(new foobar())
ReIerence, returned Irom a Iunction, i.e.:
<?php
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
?>
See aIso expIanations about returning by reIerence.
Any other expression shouId not be passed by reIerence, as the resuIt is undeIined. For exampIe, the IoIIowing
exampIes oI passing by reIerence are invaIid:
<?php
function bar() // Note the missing &
{
$a = 5;
return $a;
}
foo(bar()); // Produces fatal error since PHP 5.0.5
foo($a = 5); // Expression, not variable
foo(5); // Produces fatal error
?>
These requirements are Ior PHP 4.0.4 and Iater.
Returning References
Returning by-reIerence is useIuI when you want to use a Iunction to Iind which variabIe a reIerence shouId be
bound to. Do not use return-by-reIerence to increase perIormance, the engine is smart enough to optimize this
on its own. OnIy return reIerences when you have a vaIid technicaI reason to do it! To return reIerences, use
this syntax:
<?php
class foo {
public $value = 42;
public function &getValue() {
return $this->value;
}
}
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue; // prints the new value of $obj->value, i.e. 2.
?>
In this exampIe, the property oI the object returned by the getJalue Iunction wouId be set, not the copy, as it
wouId be without using reIerence syntax.
Note: UnIike parameter passing, here you have to use & in both pIaces - to indicate that you return by-
reIerence, not a copy as usuaI, and to indicate that reIerence binding, rather than usuaI assignment, shouId be
done Ior SmvJalue.
Note: II you try to return a reIerence Irom a Iunction with the syntax: return (Sthis-value), this wiII not work
as you are attempting to return the resuIt oI an expression, and not a variabIe, by reIerence. You can onIy
return variabIes by reIerence Irom a Iunction - nothing eIse. E_NOTICE error is issued since PHP 4.4.0 and
PHP 5.1.0 iI the code tries to return a dynamic expression or a resuIt oI the new operator.
Unsetting References
When you unset the reIerence, you just break the binding between variabIe name and variabIe content. This
does not mean that variabIe content wiII be destroyed. For exampIe:
<?php
$a = 1;
$b =& $a;
unset($a);
?>
won't unset Sb, just Sa.
Again, it might be useIuI to think about this as anaIogous to Unix unlink caII.
Spotting References
Many syntax constructs in PHP are impIemented via reIerencing mechanisms, so everything toId above about
reIerence binding aIso appIy to these constructs. Some constructs, Iike passing and returning by-reIerence, are
mentioned above. Other constructs that use reIerences are:
global References
When you decIare variabIe as global $var you are in Iact creating reIerence to a gIobaI variabIe. That means,
this is the same as:
<?php
$var =& $GLOBALS["var"];
?>
That means, Ior exampIe, that unsetting Svar won't unset gIobaI variabIe.
$this
In an object method, Sthis is aIways a reIerence to the caIIer object.
Part IV. Security
Chapter 23. Introduction
PHP is a powerIuI Ianguage and the interpreter, whether incIuded in a web server as a moduIe or executed as a
separate CGI binary, is abIe to access IiIes, execute commands and open network connections on the server.
These properties make anything run on a web server insecure by deIauIt. PHP is designed speciIicaIIy to be a
more secure Ianguage Ior writing CGI programs than PerI or C, and with correct seIection oI compiIe-time
and runtime conIiguration options, and proper coding practices, it can give you exactIy the combination oI
Ireedom and security you need.
As there are many diIIerent ways oI utiIizing PHP, there are many conIiguration options controIIing its
behaviour. A Iarge seIection oI options guarantees you can use PHP Ior a Iot oI purposes, but it aIso means
there are combinations oI these options and server conIigurations that resuIt in an insecure setup.
The conIiguration IIexibiIity oI PHP is equaIIy rivaIIed by the code IIexibiIity. PHP can be used to buiId
compIete server appIications, with aII the power oI a sheII user, or it can be used Ior simpIe server-side
incIudes with IittIe risk in a tightIy controIIed environment. How you buiId that environment, and how secure
it is, is IargeIy up to the PHP deveIoper.
This chapter starts with some generaI security advice, expIains the diIIerent conIiguration option combinations
and the situations they can be saIeIy used, and describes diIIerent considerations in coding Ior diIIerent IeveIs
oI security.
Chapter 24. General considerations
A compIeteIy secure system is a virtuaI impossibiIity, so an approach oIten used in the security proIession is
one oI baIancing risk and usabiIity. II every variabIe submitted by a user required two Iorms oI biometric
vaIidation (such as a retinaI scan and a Iingerprint), you wouId have an extremeIy high IeveI oI accountabiIity.
It wouId aIso take haII an hour to IiII out a IairIy compIex Iorm, which wouId tend to encourage users to Iind
ways oI bypassing the security.
The best security is oIten unobtrusive enough to suit the requirements without the user being prevented Irom
accompIishing their work, or over-burdening the code author with excessive compIexity. Indeed, some
security attacks are mereIy expIoits oI this kind oI overIy buiIt security, which tends to erode over time.
A phrase worth remembering: A system is onIy as good as the weakest Iink in a chain. II aII transactions are
heaviIy Iogged based on time, Iocation, transaction type, etc. but the user is onIy veriIied based on a singIe
cookie, the vaIidity oI tying the users to the transaction Iog is severeIy weakened.
When testing, keep in mind that you wiII not be abIe to test aII possibiIities Ior even the simpIest oI pages. The
input you may expect wiII be compIeteIy unreIated to the input given by a disgruntIed empIoyee, a cracker
with months oI time on their hands, or a housecat waIking across the keyboard. This is why it's best to Iook at
the code Irom a IogicaI perspective, to discern where unexpected data can be introduced, and then IoIIow how
it is modiIied, reduced, or ampIiIied.
The Internet is IiIIed with peopIe trying to make a name Ior themseIves by breaking your code, crashing your
site, posting inappropriate content, and otherwise making your day interesting. It doesn't matter iI you have a
smaII or Iarge site, you are a target by simpIy being onIine, by having a server that can be connected to. Many
cracking programs do not discern by size, they simpIy trawI massive IP bIocks Iooking Ior victims. Try not to
become one.
Chapter 25. Installed as CGI binary
Possible attacks
Using PHP as a CGI binary is an option Ior setups that Ior some reason do not wish to integrate PHP as a
moduIe into server soItware (Iike Apache), or wiII use PHP with diIIerent kinds oI CGI wrappers to create saIe
chroot and setuid environments Ior scripts. This setup usuaIIy invoIves instaIIing executabIe PHP binary to the
web server cgi-bin directory. CERT advisory CA-96.11 recommends against pIacing any interpreters into
cgi-bin. Even iI the PHP binary can be used as a standaIone interpreter, PHP is designed to prevent the attacks
this setup makes possibIe:
Accessing system IiIes: http.mv.hostcgi-binphp?etcpasswd
The query inIormation in a URL aIter the question mark (?) is passed as command Iine arguments to
the interpreter by the CGI interIace. UsuaIIy interpreters open and execute the IiIe speciIied as the Iirst
argument on the command Iine.
When invoked as a CGI binary, PHP reIuses to interpret the command Iine arguments.
Accessing any web document on server: http.mv.hostcgi-binphpsecretdoc.html
The path inIormation part oI the URL aIter the PHP binary name, secretdoc.html is conventionaIIy
used to speciIy the name oI the IiIe to be opened and interpreted by the CGI program. UsuaIIy some
web server conIiguration directives (Apache: Action) are used to redirect requests to documents Iike
http.mv.hostsecretscript.php to the PHP interpreter. With this setup, the web server Iirst checks the
access permissions to the directory secret, and aIter that creates the redirected request
http.mv.hostcgi-binphpsecretscript.php. UnIortunateIy, iI the request is originaIIy given in this
Iorm, no access checks are made by web server Ior IiIe secretscript.php, but onIy Ior the cgi-binphp
IiIe. This way any user abIe to access cgi-binphp is abIe to access any protected document on the web
server.
In PHP, compiIe-time conIiguration option --enabIe-Iorce-cgi-redirect and runtime conIiguration
directives docroot and userdir can be used to prevent this attack, iI the server document tree has any
directories with access restrictions. See beIow Ior IuII the expIanation oI the diIIerent combinations.
Case 1: only public files served
II your server does not have any content that is not restricted by password or ip based access controI, there is
no need Ior these conIiguration options. II your web server does not aIIow you to do redirects, or the server
does not have a way to communicate to the PHP binary that the request is a saIeIy redirected request, you can
speciIy the option --enabIe-Iorce-cgi-redirect to the conIigure script. You stiII have to make sure your PHP
scripts do not reIy on one or another way oI caIIing the script, neither by directIy http.mv.hostcgi-
binphpdirscript.php nor by redirection http.mv.hostdirscript.php.
Redirection can be conIigured in Apache by using AddHandIer and Action directives (see beIow).
Case 2: using --enable-force-cgi-redirect
This compiIe-time option prevents anyone Irom caIIing PHP directIy with a URL Iike http.mv.hostcgi-
binphpsecretdirscript.php. Instead, PHP wiII onIy parse in this mode iI it has gone through a web server
redirect ruIe.
UsuaIIy the redirection in the Apache conIiguration is done with the IoIIowing directives:
Action php-script /cgi-bin/php
AddHandler php-script .php
This option has onIy been tested with the Apache web server, and reIies on Apache to set the non-standard
CGI environment variabIe REDIRECT_STATUS on redirected requests. II your web server does not support any
way oI teIIing iI the request is direct or redirected, you cannot use this option and you must use one oI the
other ways oI running the CGI version documented here.
Case 3: setting doc_root or user_dir
To incIude active content, Iike scripts and executabIes, in the web server document directories is sometimes
considered an insecure practice. II, because oI some conIiguration mistake, the scripts are not executed but
dispIayed as reguIar HTML documents, this may resuIt in Ieakage oI inteIIectuaI property or security
inIormation Iike passwords. ThereIore many sysadmins wiII preIer setting up another directory structure Ior
scripts that are accessibIe onIy through the PHP CGI, and thereIore aIways interpreted and not dispIayed as
such.
AIso iI the method Ior making sure the requests are not redirected, as described in the previous section, is not
avaiIabIe, it is necessary to set up a script docroot that is diIIerent Irom web document root.
You can set the PHP script document root by the conIiguration directive docroot in the conIiguration IiIe, or
you can set the environment variabIe PHP_DOCUMENT_ROOT. II it is set, the CGI version oI PHP wiII aIways
construct the IiIe name to open with this doc_root and the path inIormation in the request, so you can be sure
no script is executed outside this directory (except Ior user_dir beIow).
Another option usabIe here is userdir. When userdir is unset, onIy thing controIIing the opened IiIe name is
doc_root. Opening a URL Iike http.mv.host~userdoc.php does not resuIt in opening a IiIe under users
home directory, but a IiIe caIIed ~userdoc.php under docroot (yes, a directory name starting with a tiIde |~]).
II userdir is set to Ior exampIe publicphp, a request Iike http.mv.host~userdoc.php wiII open a IiIe caIIed
doc.php under the directory named publicphp under the home directory oI the user. II the home oI the user is
homeuser, the IiIe executed is homeuserpublicphpdoc.php.
user_dir expansion happens regardIess oI the doc_root setting, so you can controI the document root and
user directory access separateIy.
Case 4: PHP parser outside of web tree
A very secure option is to put the PHP parser binary somewhere outside oI the web tree oI IiIes. In
usrlocalbin, Ior exampIe. The onIy reaI downside to this option is that you wiII now have to put a Iine
simiIar to:
#!/usr/local/bin/php
as the Iirst Iine oI any IiIe containing PHP tags. You wiII aIso need to make the IiIe executabIe. That is, treat it
exactIy as you wouId treat any other CGI script written in PerI or sh or any other common scripting Ianguage
which uses the ! sheII-escape mechanism Ior Iaunching itseII.
To get PHP to handIe PATH_INFO and PATH_TRANSLATED inIormation correctIy with this setup, the PHP parser
shouId be compiIed with the --enabIe-discard-path conIigure option.
Chapter 26. Installed as an Apache module
When PHP is used as an Apache moduIe it inherits Apache's user permissions (typicaIIy those oI the "nobody"
user). This has severaI impacts on security and authorization. For exampIe, iI you are using PHP to access a
database, unIess that database has buiIt-in access controI, you wiII have to make the database accessibIe to the
"nobody" user. This means a maIicious script couId access and modiIy the database, even without a username
and password. It's entireIy possibIe that a web spider couId stumbIe across a database administrator's web
page, and drop aII oI your databases. You can protect against this with Apache authorization, or you can
design your own access modeI using LDAP, .htaccess IiIes, etc. and incIude that code as part oI your PHP
scripts.
OIten, once security is estabIished to the point where the PHP user (in this case, the apache user) has very
IittIe risk attached to it, it is discovered that PHP is now prevented Irom writing any IiIes to user directories.
Or perhaps it has been prevented Irom accessing or changing databases. It has equaIIy been secured Irom
writing good and bad IiIes, or entering good and bad database transactions.
A Irequent security mistake made at this point is to aIIow apache root permissions, or to escaIate apache's
abiIities in some other way.
EscaIating the Apache user's permissions to root is extremeIy dangerous and may compromise the entire
system, so sudo'ing, chroot'ing, or otherwise running as root shouId not be considered by those who are not
security proIessionaIs.
There are some simpIer soIutions. By using openbasedir you can controI and restrict what directories are
aIIowed to be used Ior PHP. You can aIso set up apache-onIy areas, to restrict aII web based activity to non-
user, or non-system, IiIes.
Chapter 27. Filesystem Security
Table of Contents
Null bytes related issues
PHP is subject to the security buiIt into most server systems with respect to permissions on a IiIe and directory
basis. This aIIows you to controI which IiIes in the IiIesystem may be read. Care shouId be taken with any IiIes
which are worId readabIe to ensure that they are saIe Ior reading by aII users who have access to that
IiIesystem.
Since PHP was designed to aIIow user IeveI access to the IiIesystem, it's entireIy possibIe to write a PHP script
that wiII aIIow you to read system IiIes such as /etc/passwd, modiIy your ethernet connections, send massive
printer jobs out, etc. This has some obvious impIications, in that you need to ensure that the IiIes that you read
Irom and write to are the appropriate ones.
Consider the IoIIowing script, where a user indicates that they'd Iike to deIete a IiIe in their home directory.
This assumes a situation where a PHP web interIace is reguIarIy used Ior IiIe management, so the Apache user
is aIIowed to deIete IiIes in the user home directories.
Example 27.1. Poor variable checking leads to....
<?php
// remove a file from the user's home directory
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
unlink("$homedir/$userfile");
echo "The file has been deleted!";
?>
5ince the username and the filename are postable from a user form, they can submit a
username and a filename belonging to someone else, and delete it even if they're not
supposed to be allowed to do so. n this case, you'd want to use some other form of
authentication. Consider what could happen if the variables submitted were "../etc/"
and "passwd". The code would then effectively read:
Example 27.2. ... A filesystem attack
<?php
// removes a file from anywhere on the hard drive that
// the PHP user has access to. If PHP has root access:
$username = $_POST['user_submitted_name']; // "../etc"
$userfile = $_POST['user_submitted_filename']; // "passwd"
$homedir = "/home/$username"; // "/home/../etc"
unlink("$homedir/$userfile"); // "/home/../etc/passwd"
echo "The file has been deleted!";
?>
There are two important measures you should take to prevent these issues.
Only allow limited permissions to the PHP web user binary.
Check all variables which are submitted.
Here is an improved script:
Example 27.3. More secure file name checking
<?php
// removes a file from the hard drive that
// the PHP user has access to.
$username = $_SERVER['REMOTE_USER']; // using an authentication mechanisim
$userfile = basename($_POST['user_submitted_filename']);
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (file_exists($filepath) && unlink($filepath)) {
$logstring = "Deleted $filepath\n";
} else {
$logstring = "Failed to delete $filepath\n";
}
$fp = fopen("/home/logging/filedelete.log", "a");
fwrite($fp, $lo gstring);
fclose($fp);
echo htmlentities($logstring, ENT_QUOTES);
?>
However, even this is not without its flaws. f your authentication system allowed users
to create their own user logins, and a user chose the login "../etc/", the system is once
again exposed. For this reason, you may prefer to write a more customized check:
Example 27.4. More secure file name checking
<?php
$username = $_SERVER['REMOTE_USER']; // using an authentication mechanisim
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile))
{
die("Bad username/filename");
}
//etc...
?>
Depending on your operating system, there are a wide variety oI IiIes which you shouId be concerned about,
incIuding device entries (/dev/ or COM1), conIiguration IiIes (/etc/ IiIes and the .ini IiIes), weII known IiIe
storage areas (/home/, My Documents), etc. For this reason, it's usuaIIy easier to create a poIicy where you
Iorbid everything except Ior what you expIicitIy aIIow.
Null bytes related issues
As PHP uses the underIying C Iunctions Ior IiIesystem reIated operations, it may handIe nuII bytes in a quite
unexpected way. As nuII bytes denote the end oI a string in C, strings containing them won't be considered
entireIy but rather onIy untiI a nuII byte occurs. The IoIIowing exampIe shows a vuInerabIe code that
demonstrates this probIem:
Example 27.5. Script vulnerable to null bytes
<?php
$file = $_GET['file']; // "../../etc/passwd\0"
if (file_exists('/home/wwwrun/'.$file.'.php')) {
// file_exists will return true as the file /home/wwwrun/../../etc/passwd exists
include '/home/wwwrun/'.$file.'.php';
// the file /etc/passwd will be included
}
?>
ThereIore, any tainted string that is used in a IiIesystem operation shouId aIways be vaIidated properIy. Here is
a better version oI the previous exampIe:
Example 27.6. Correctly validating the input
<?php
$file = $_GET['file'];
// Whitelisting possible values
switch ($file) {
case 'main':
case 'foo':
case 'bar':
include '/home/wwwrun/include/'.$file.'.php';
break;
default:
include '/home/wwwrun/include/main.php';
}
?>
Chapter 28. Database Security
Nowadays, databases are cardinaI components oI any web based appIication by enabIing websites to provide
varying dynamic content. Since very sensitive or secret inIormation can be stored in a database, you shouId
strongIy consider protecting your databases.
To retrieve or to store any inIormation you need to connect to the database, send a Iegitimate query, Ietch the
resuIt, and cIose the connection. Nowadays, the commonIy used query Ianguage in this interaction is the
Structured Query Language (SQL). See how an attacker can tamper with an SQL query.
As you can surmise, PHP cannot protect your database by itseII. The IoIIowing sections aim to be an
introduction into the very basics oI how to access and manipuIate databases within PHP scripts.
Keep in mind this simpIe ruIe: deIense in depth. The more pIaces you take action to increase the protection oI
your database, the Iess probabiIity oI an attacker succeeding in exposing or abusing any stored inIormation.
Good design oI the database schema and the appIication deaIs with your greatest Iears.
Designing Databases
The Iirst step is aIways to create the database, unIess you want to use one Irom a third party. When a database
is created, it is assigned to an owner, who executed the creation statement. UsuaIIy, onIy the owner (or a
superuser) can do anything with the objects in that database, and in order to aIIow other users to use it,
priviIeges must be granted.
AppIications shouId never connect to the database as its owner or a superuser, because these users can execute
any query at wiII, Ior exampIe, modiIying the schema (e.g. dropping tabIes) or deIeting its entire content.
You may create diIIerent database users Ior every aspect oI your appIication with very Iimited rights to
database objects. The most required priviIeges shouId be granted onIy, and avoid that the same user can
interact with the database in diIIerent use cases. This means that iI intruders gain access to your database
using your appIications credentiaIs, they can onIy eIIect as many changes as your appIication can.
You are encouraged not to impIement aII the business Iogic in the web appIication (i.e. your script), instead do
it in the database schema using views, triggers or ruIes. II the system evoIves, new ports wiII be intended to
open to the database, and you have to re-impIement the Iogic in each separate database cIient. Over and above,
triggers can be used to transparentIy and automaticaIIy handIe IieIds, which oIten provides insight when
debugging probIems with your appIication or tracing back transactions.
Connecting to Database
You may want to estabIish the connections over SSL to encrypt cIient/server communications Ior increased
security, or you can use ssh to encrypt the network connection between cIients and the database server. II
either oI these is used, then monitoring your traIIic and gaining inIormation about your database wiII be
diIIicuIt Ior a wouId-be attacker.
Encrypted Storage Model
SSL/SSH protects data traveIIing Irom the cIient to the server, SSL/SSH does not protect the persistent data
stored in a database. SSL is an on-the-wire protocoI.
Once an attacker gains access to your database directIy (bypassing the webserver), the stored sensitive data
may be exposed or misused, unIess the inIormation is protected by the database itseII. Encrypting the data is a
good way to mitigate this threat, but very Iew databases oIIer this type oI data encryption.
The easiest way to work around this probIem is to Iirst create your own encryption package, and then use it
Irom within your PHP scripts. PHP can assist you in this with severaI extensions, such as Mcrypt and Mhash,
covering a wide variety oI encryption aIgorithms. The script encrypts the data beIore inserting it into the
database, and decrypts it when retrieving. See the reIerences Ior Iurther exampIes oI how encryption works.
In case oI truIy hidden data, iI its raw representation is not needed (i.e. not be dispIayed), hashing may aIso be
taken into consideration. The weII-known exampIe Ior the hashing is storing the MD5 hash oI a password in a
database, instead oI the password itseII. See aIso crypt() and md5().
Example 28.1. Using hashed password field
<?php
// storing password hash
$query = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",
pg_escape_string($username), md5($password));
$result = pg_query($connection, $query);
// querying if user submitted the right password
$query = sprintf("SELECT 1 FROM users WHERE name='%s' AND pwd='%s';",
pg_escape_string($username), md5($password));
$result = pg_query($connection, $query);
if (pg_num_rows($result) > 0) {
echo 'Welcome, $username!';
} else {
echo 'Authentication failed for $username.';
}
?>
SQLInjection
Many web deveIopers are unaware oI how SQL queries can be tampered with, and assume that an SQL query
is a trusted command. It means that SQL queries are abIe to circumvent access controIs, thereby bypassing
standard authentication and authorization checks, and sometimes SQL queries even may aIIow access to host
operating system IeveI commands.
Direct SQL Command Injection is a technique where an attacker creates or aIters existing SQL commands to
expose hidden data, or to override vaIuabIe ones, or even to execute dangerous system IeveI commands on the
database host. This is accompIished by the appIication taking user input and combining it with static
parameters to buiId a SQL query. The IoIIowing exampIes are based on true stories, unIortunateIy.
Owing to the Iack oI input vaIidation and connecting to the database on behaII oI a superuser or the one who
can create users, the attacker may create a superuser in your database.
Example 28.2. Splitting the result set into pages ... and making superusers (PostgreSQL)
<?php
$offset = $argv[0]; // beware, no input validation!
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
$result = pg_query($conn, $query);
?>
Normal users click on the 'next', 'prev' links where the $o||set is encoded into the URL.
The script expects that the incoming $o||set is a decimal number. However, what if
someone tries to break in by appending a urlencode()'d form of the following to the URL
0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
select 'crack', usesysid, 't','t','crack'
from pg_shadow where usename='postgres';
--
f it happened, then the script would present a superuser access to him. Note that 0; is
to supply a valid offset to the original query and to terminate it.
Note: It is common technique to Iorce the SQL parser to ignore the rest oI the query written by the deveIoper
with -- which is the comment sign in SQL.
A IeasibIe way to gain passwords is to circumvent your search resuIt pages. The onIy thing the attacker needs
to do is to see iI there are any submitted variabIes used in SQL statements which are not handIed properIy.
These IiIters can be set commonIy in a preceding Iorm to customize hHERE. ORDER BY. LIMIT and
OFFSET cIauses in SELECT statements. II your database supports the UNION construct, the attacker may try
to append an entire query to the originaI one to Iist passwords Irom an arbitrary tabIe. Using encrypted
password IieIds is strongIy encouraged.
Example 28.3. Listing out articles ... and some passwords (any database server)
<?php
$query = "SELECT id, name, inserted, size FROM products
WHERE size = '$size'
ORDER BY $order LIMIT $limit, $offset;";
$result = odbc_exec($conn, $query);
?>
The static part of the query can be combined with another 5ElECT statement which
reveals all passwords:
'
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable;
--
f this query (playing with the ' and --) were assigned to one of the variables used in
$query, the query beast awakened.
SQL UPDATE's are aIso susceptibIe to attack. These queries are aIso threatened by chopping and appending
an entireIy new query to it. But the attacker might IiddIe with the SET cIause. In this case some schema
inIormation must be possessed to manipuIate the query successIuIIy. This can be acquired by examining the
Iorm variabIe names, or just simpIy brute Iorcing. There are not so many naming conventions Ior IieIds
storing passwords or usernames.
Example 28.4. From resetting a password ... to gaining more privileges (any database server)
<?php
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
?>
But a malicious user sumbits the value ' or uid like'%admin%'; -- to $uid to change the
admin's password, or simply sets $pwd to "hehehe', admin='yes', trusted=J00 " (with a
trailing space) to gain more privileges. Then, the query will be twisted:
<?php
// $uid == ' or uid like'%admin%'; --
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";
// $pwd == "hehehe', admin='yes', trusted=100 "
$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
...;";
?>
A Irightening exampIe how operating system IeveI commands can be accessed on some database hosts.
Example 28.5. Attacking the database hosts operating system (MSSQL Server)
<?php
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";
$result = mssql_query($query);
?>
f attacker submits the value a%' exec master..xp_cmdshell 'net user test testpass
/ADD' -- to $prod, then the $query will be:
<?php
$query = "SELECT * FROM products
WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);
?>
M55OL 5erver executes the 5OL statements in the batch including a command to add a
new user to the local accounts database. f this application were running as sa and the
M55OL5ERVER service is running with sufficient privileges, the attacker would now
have an account with which to access this machine.
Note: Some oI the exampIes above is tied to a speciIic database server. This does not mean that a simiIar
attack is impossibIe against other products. Your database server may be simiIarIy vuInerabIe in another
manner.
Avoiding techniques
You may pIead that the attacker must possess a piece oI inIormation about the database schema in most
exampIes. You are right, but you never know when and how it can be taken out, and iI it happens, your
database may be exposed. II you are using an open source, or pubIicIy avaiIabIe database handIing package,
which may beIong to a content management system or Iorum, the intruders easiIy produce a copy oI a piece oI
your code. It may be aIso a security risk iI it is a poorIy designed one.
These attacks are mainIy based on expIoiting the code not being written with security in mind. Never trust any
kind oI input, especiaIIy that which comes Irom the cIient side, even though it comes Irom a seIect box, a
hidden input IieId or a cookie. The Iirst exampIe shows that such a bIameIess query can cause disasters.
Never connect to the database as a superuser or as the database owner. Use
always customized users with very limited privileges.
Check if the given input has the expected data type. PHP has a wide range of
input validating functions, from the simplest ones found in Variable Functions and
in Character Type Functions (e.g. is_numeric(), ctype_digit() respectively) and
onwards to the Perl compatible Regular Expressions support.
II the appIication waits Ior numericaI input, consider veriIying data with isnumeric(), or siIentIy
change its type using settype(), or use its numeric representation by sprintI().
Example 28.6. A more secure way to compose a query for paging
<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// please note %d in the format string, using %s would be meaningless
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;"
,
$offset);
?>
Ouote each non numeric user supplied value that is passed to the database with
the database-specific string escape function (e.g. mysql_escape_string(),
sql_escape_string(), etc.). f a database-specific string escape mechanism is
not available, the addslashes() and str_replace() functions may be useful
(depending on database type). 5ee the first example. As the example shows,
adding quotes to the static part of the query is not enough, making this query
easily crackable.
Do not print out any database specific information, especially about the schema,
by fair means or foul. 5ee also Error Reporting and Error Handling and Logging
Functions.
You may use stored procedures and previously defined cursors to abstract data
access so that users do not directly access tables or views, but this solution has
another impacts.
Besides these, you beneIit Irom Iogging queries either within your script or by the database itseII, iI it
supports Iogging. ObviousIy, the Iogging is unabIe to prevent any harmIuI attempt, but it can be heIpIuI to
trace back which appIication has been circumvented. The Iog is not useIuI by itseII, but through the
inIormation it contains. More detaiI is generaIIy better than Iess.
Chapter 29. Error Reporting
With PHP security, there are two sides to error reporting. One is beneIiciaI to increasing security, the other is
detrimentaI.
A standard attack tactic invoIves proIiIing a system by Ieeding it improper data, and checking Ior the kinds,
and contexts, oI the errors which are returned. This aIIows the system cracker to probe Ior inIormation about
the server, to determine possibIe weaknesses. For exampIe, iI an attacker had gIeaned inIormation about a
page based on a prior Iorm submission, they may attempt to override variabIes, or modiIy them:
Example 29.1. Attacking Variables with a custom HTML page
<form method="post" action="attacktarget?username=badfoo&amp;password=badfoo">
<input type="hidden" name="username" value="badfoo" />
<input type="hidden" name="password" value="badfoo" />
</form>
The PHP errors which are normaIIy returned can be quite heIpIuI to a deveIoper who is trying to debug a
script, indicating such things as the Iunction or IiIe that IaiIed, the PHP IiIe it IaiIed in, and the Iine number
which the IaiIure occurred in. This is aII inIormation that can be expIoited. It is not uncommon Ior a php
deveIoper to use showsource(), highIightstring(), or highIightIiIe() as a debugging measure, but in a Iive
site, this can expose hidden variabIes, unchecked syntax, and other dangerous inIormation. EspeciaIIy
dangerous is running code Irom known sources with buiIt-in debugging handIers, or using common debugging
techniques. II the attacker can determine what generaI technique you are using, they may try to brute-Iorce a
page, by sending various common debugging strings:
Example 29.2. Exploiting common debugging variables
<form method="post" action="attacktarget?errors=Y&amp;showerrors=1&amp;debug=1">
<input type="hidden" name="errors" value="Y" />
<input type="hidden" name="showerrors" value="1" />
<input type="hidden" name="debug" value="1" />
</form>
RegardIess oI the method oI error handIing, the abiIity to probe a system Ior errors Ieads to providing an
attacker with more inIormation.
For exampIe, the very styIe oI a generic PHP error indicates a system is running PHP. II the attacker was
Iooking at an .htmI page, and wanted to probe Ior the back-end (to Iook Ior known weaknesses in the system),
by Ieeding it the wrong data they may be abIe to determine that a system was buiIt with PHP.
A Iunction error can indicate whether a system may be running a speciIic database engine, or give cIues as to
how a web page or programmed or designed. This aIIows Ior deeper investigation into open database ports, or
to Iook Ior speciIic bugs or weaknesses in a web page. By Ieeding diIIerent pieces oI bad data, Ior exampIe,
an attacker can determine the order oI authentication in a script, (Irom the Iine number errors) as weII as probe
Ior expIoits that may be expIoited in diIIerent Iocations in the script.
A IiIesystem or generaI PHP error can indicate what permissions the web server has, as weII as the structure
and organization oI IiIes on the web server. DeveIoper written error code can aggravate this probIem, Ieading
to easy expIoitation oI IormerIy "hidden" inIormation.
There are three major soIutions to this issue. The Iirst is to scrutinize aII Iunctions, and attempt to compensate
Ior the buIk oI the errors. The second is to disabIe error reporting entireIy on the running code. The third is to
use PHP's custom error handIing Iunctions to create your own error handIer. Depending on your security
poIicy, you may Iind aII three to be appIicabIe to your situation.
One way oI catching this issue ahead oI time is to make use oI PHP's own errorreporting(), to heIp you
secure your code and Iind variabIe usage that may be dangerous. By testing your code, prior to depIoyment,
with EALL, you can quickIy Iind areas where your variabIes may be open to poisoning or modiIication in
other ways. Once you are ready Ior depIoyment, you shouId either disabIe error reporting compIeteIy by
setting errorreporting() to 0, or turn oII the error dispIay using the php.ini option displaverrors, to insuIate
your code Irom probing. II you choose to do the Iatter, you shouId aIso deIine the path to your Iog IiIe using
the errorlog ini directive, and turn logerrors on.
Example 29.3. Finding dangerous variables with E_ALL
<?php
if ($username) { // Not initialized or checked before usage
$good_login = 1;
}
if ($good_login == 1) { // If above test fails, not initialized or checked before usage
readfile ("/highly/sensitive/data/index.html");
}
?>
Chapter 30. Using Register Globals
Warning
This Ieature is DEPRECATED and REMOJED as oI PHP 6.0.0. ReIying on this Ieature is highIy discouraged.
Perhaps the most controversiaI change in PHP is when the deIauIt vaIue Ior the PHP directive registergIobaIs
went Irom ON to OFF in PHP 4.2.0. ReIiance on this directive was quite common and many peopIe didn't
even know it existed and assumed it's just how PHP works. This page wiII expIain how one can write insecure
code with this directive but keep in mind that the directive itseII isn't insecure but rather it's the misuse oI it.
When on, registergIobaIs wiII inject your scripts with aII sorts oI variabIes, Iike request variabIes Irom
HTML Iorms. This coupIed with the Iact that PHP doesn't require variabIe initiaIization means writing
insecure code is that much easier. It was a diIIicuIt decision, but the PHP community decided to disabIe this
directive by deIauIt. When on, peopIe use variabIes yet reaIIy don't know Ior sure where they come Irom and
can onIy assume. InternaI variabIes that are deIined in the script itseII get mixed up with request data sent by
users and disabIing registergIobaIs changes this. Let's demonstrate with an exampIe misuse oI
registergIobaIs:
Example 30.1. Example misuse with register_globals on
<?php
// define $authorized = true only if user is authenticated
if (authenticated_user()) {
$authorized = true;
}
// Because we didn't first initialize $authorized as false, this might be
// defined through register_globals, like from GET auth.php?authorized=1
// So, anyone can be seen as authenticated!
if ($authorized) {
include "/highly/sensitive/data.php";
}
?>
When registergIobaIs on, our Iogic above may be compromised. When oII, Sauthori:ed can't be set via
request so it'II be Iine, aIthough it reaIIy is generaIIy a good programming practice to initiaIize variabIes Iirst.
For exampIe, in our exampIe above we might have Iirst done Sauthori:ed false. Doing this Iirst means our
above code wouId work with registergIobaIs on or oII as users by deIauIt wouId be unauthorized.
Another exampIe is that oI sessions. When registergIobaIs on, we couId aIso use Susername in our exampIe
beIow but again you must reaIize that Susername couId aIso come Irom other means, such as GET (through
the URL).
Example 30.2. Example use of sessions with register_globals on or off
<?php
// We wouldn't know where $username came from but do know $_SESSION is
// for session data
if (isset($_SESSION['username'])) {
echo "Hello <b>{$_SESSION['username']}</b>";
} else {
echo "Hello <b>Guest</b><br />";
echo "Would you like to login?";
}
?>
It's even possibIe to take preventative measures to warn when Iorging is being attempted. II you know ahead
oI time exactIy where a variabIe shouId be coming Irom, you can check to see iI the submitted data is coming
Irom an inappropriate kind oI submission. WhiIe it doesn't guarantee that data has not been Iorged, it does
require an attacker to guess the right kind oI Iorging. II you don't care where the request data comes Irom, you
can use SREQUEST as it contains a mix oI GET, POST and COOKIE data. See aIso the manuaI section on
using variabIes Irom outside oI PHP.
Example 30.3. Detecting simple variable poisoning
<?php
if (isset($_COOKIE['MAGIC_COOKIE'])) {
// MAGIC_COOKIE comes from a cookie.
// Be sure to validate the cookie data!
} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {
mail("admin@example.com", "Possible breakin attempt", $_SERVER['REMOTE_ADDR']);
echo "Security violation, admin has been alerted.";
exit;
} else {
// MAGIC_COOKIE isn't set through this REQUEST
}
?>
OI course, simpIy turning oII registergIobaIs does not mean your code is secure. For every piece oI data that
is submitted, it shouId aIso be checked in other ways. AIways vaIidate your user data and initiaIize your
variabIes! To check Ior uninitiaIized variabIes you may turn up errorreporting() to show E_NOTICE IeveI
errors.
For inIormation about emuIating registergIobaIs being On or OII, see this FAQ.
Superglobals: availability note : Since PHP 4.1.0, supergIobaI arrays such as SGET , SPOST, and
SSERJER, etc. have been avaiIabIe. For more inIormation, read the manuaI section on supergIobaIs
Chapter 31. User Submitted Data
The greatest weakness in many PHP programs is not inherent in the Ianguage itseII, but mereIy an issue oI
code not being written with security in mind. For this reason, you shouId aIways take the time to consider the
impIications oI a given piece oI code, to ascertain the possibIe damage iI an unexpected variabIe is submitted
to it.
Example 31.1. Dangerous Variable Usage
<?php
// remove a file from the user's home directory... or maybe
// somebody else's?
unlink ($evil_var);
// Write logging of their access... or maybe an /etc/passwd entry?
fwrite ($fp, $evil_var);
// Execute something trivial.. or rm -rf *?
system ($evil_var);
exec ($evil_var);
?>
You shouId aIways careIuIIy examine your code to make sure that any variabIes being submitted Irom a web
browser are being properIy checked, and ask yourseII the IoIIowing questions:
WiII this script onIy aIIect the intended IiIes?
Can unusuaI or undesirabIe data be acted upon?
Can this script be used in unintended ways?
Can this be used in conjunction with other scripts in a negative manner?
WiII any transactions be adequateIy Iogged?
By adequateIy asking these questions whiIe writing the script, rather than Iater, you prevent an unIortunate re-
write when you need to increase your security. By starting out with this mindset, you won't guarantee the
security oI your system, but you can heIp improve it.
You may aIso want to consider turning oII registergIobaIs, magicquotes, or other convenience settings
which may conIuse you as to the vaIidity, source, or vaIue oI a given variabIe. Working with PHP in
errorreporting(EALL) mode can aIso heIp warn you about variabIes being used beIore they are checked or
initiaIized (so you can prevent unusuaI data Irom being operated upon).
Chapter 32. Magic Quotes
Warning
This Ieature is DEPRECATED and REMOJED as oI PHP 6.0.0. ReIying on this Ieature is highIy discouraged.
Magic Quotes is a process that automagicaIIy escapes incoming data to the PHP script. It's preIerred to code
with magic quotes oII and to instead escape the data at runtime, as needed.
What are Magic Quotes
When on, aII (singIe-quote), " (doubIe quote), (backsIash) and NULL characters are escaped with a
backsIash automaticaIIy. This is identicaI to what addsIashes() does.
There are three magic quote directives:
magicquotesgpc
AIIects HTTP Request data (GET, POST, and COOKIE). Cannot be set at runtime, and deIauIts to on
in PHP.
See aIso getmagicquotesgpc().
magicquotesruntime
II enabIed, most Iunctions that return data Irom an externaI source, incIuding databases and text IiIes,
wiII have quotes escaped with a backsIash. Can be set at runtime, and deIauIts to off in PHP.
See aIso setmagicquotesruntime() and getmagicquotesruntime().
magicquotessybase
II enabIed, a singIe-quote is escaped with a singIe-quote instead oI a backsIash. II on, it compIeteIy
overrides magicquotesgpc. Having both directives enabIed means onIy singIe quotes are escaped as
. DoubIe quotes, backsIashes and NULL's wiII remain untouched and unescaped.
Why use Magic Quotes
UseIuI Ior beginners
Magic quotes are impIemented in PHP to heIp code written by beginners Irom being dangerous.
AIthough SQL Injection is stiII possibIe with magic quotes on, the risk is reduced.
Convenience
For inserting data into a database, magic quotes essentiaIIy runs addsIashes() on aII Get, Post, and
Cookie data, and does so automagicaIIy.
Why not to use Magic Quotes
PortabiIity
Assuming it to be on, or oII, aIIects portabiIity. Use getmagicquotesgpc() to check Ior this, and
code accordingIy.
PerIormance
Because not every piece oI escaped data is inserted into a database, there is a perIormance Ioss Ior
escaping aII this data. SimpIy caIIing on the escaping Iunctions (Iike addsIashes()) at runtime is more
eIIicient.
AIthough php.ini-dist enabIes these directives by deIauIt, php.ini-recommended disabIes it. This
recommendation is mainIy due to perIormance reasons.
Inconvenience
Because not aII data needs escaping, it's oIten annoying to see escaped data where it shouIdn't be. For
exampIe, emaiIing Irom a Iorm, and seeing a bunch oI \' within the emaiI. To Iix, this may require
excessive use oI stripsIashes().
Disabling Magic Quotes
The magicquotesgpc directive may onIy be disabIed at the system IeveI, and not at runtime. In otherwords,
use oI iniset() is not an option.
Example 32.1. Disabling magic quotes server side
An exampIe that sets the vaIue oI these directives to Off in php.ini. For additionaI detaiIs, read the manuaI
section titIed How to change conIiguration settings.
; Magic quotes
;
; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = Off
; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off
; Use Sybase-style magic quotes (escape ' with '' instead of \').
magic_quotes_sybase = Off
II access to the server conIiguration is unavaiIabIe, use oI .htaccess is aIso an option. For exampIe:
php_flag magic_quotes_gpc Off
In the interest oI writing portabIe code (code that works in any environment), Iike iI setting at the server IeveI
is not possibIe, here's an exampIe to disabIe magicquotesgpc at runtime. This method is ineIIicient so it's
preIerred to instead set the appropriate directives eIsewhere.
Example 32.2. Disabling magic quotes at runtime
<?php
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value)
{
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);
return $value;
}
$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}
?>
Chapter 33. Hiding PHP
In generaI, security by obscurity is one oI the weakest Iorms oI security. But in some cases, every IittIe bit oI
extra security is desirabIe.
A Iew simpIe techniques can heIp to hide PHP, possibIy sIowing down an attacker who is attempting to
discover weaknesses in your system. By setting exposephp oII in your php.ini IiIe, you reduce the amount
oI inIormation avaiIabIe to them.
Another tactic is to conIigure web servers such as apache to parse diIIerent IiIetypes through PHP, either with
an .htaccess directive, or in the apache conIiguration IiIe itseII. You can then use misIeading IiIe extensions:
Example 33.1. Hiding PHP as another language
# Make PHP code look like other code types
AddType application/x-httpd-php .asp .py .pl
Or obscure it compIeteIy:
Example 33.2. Using unknown types for PHP extensions
# Make PHP code look like unknown types
AddType application/x-httpd-php .bop .foo .133t
Or hide it as HTML code, which has a sIight perIormance hit because aII HTML wiII be parsed through the
PHP engine:
Example 33.3. Using HTML types for PHP extensions
# Make all PHP code look like HTML
AddType application/x-httpd-php .htm .html
For this to work eIIectiveIy, you must rename your PHP IiIes with the above extensions. WhiIe it is a Iorm oI
security through obscurity, it's a minor preventative measure with Iew drawbacks.
Chapter 34. Keeping Current
PHP, Iike any other Iarge system, is under constant scrutiny and improvement. Each new version wiII oIten
incIude both major and minor changes to enhance security and repair any IIaws, conIiguration mishaps, and
other issues that wiII aIIect the overaII security and stabiIity oI your system.
Like other system-IeveI scripting Ianguages and programs, the best approach is to update oIten, and maintain
awareness oI the Iatest versions and their changes.
Part V. Features
Chapter 35. HTTP authentication with PHP
The HTTP Authentication hooks in PHP are onIy avaiIabIe when it is running as an Apache moduIe and is
hence not avaiIabIe in the CGI version. In an Apache moduIe PHP script, it is possibIe to use the header()
Iunction to send an "Authentication Required" message to the cIient browser causing it to pop up a
Username/Password input window. Once the user has IiIIed in a username and a password, the URL
containing the PHP script wiII be caIIed again with the predeIined variabIes PHPAUTHUSER,
PHPAUTHPh, and AUTHTYPE set to the user name, password and authentication type respectiveIy.
These predeIined variabIes are Iound in the $SERVER and SHTTPSERJERJARS arrays. Both "Basic" and
"Digest" (since PHP 5.1.0) authentication methods are supported. See the header() Iunction Ior more
inIormation.
PHP Version Note: SupergIobaIs, such as $SERVER, became avaiIabIe in PHP 4.1.0.
SHTTPSERJERJARS has been avaiIabIe since PHP 3.
An exampIe script Iragment which wouId Iorce cIient authentication on a page is as IoIIows:
Example 35.1. Basic HTTPAuthentication example
<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Text to send if user hits Cancel button';
exit;
} else {
echo "<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>You entered {$_SERVER['PHP_AUTH_PW']} as your password.</p>";
}
?>
Example 35.2. Digest HTTPAuthentication example
This exampIe shows you how to impIement a simpIe Digest HTTP authentication script. For more inIormation
read the RFC 2617.
<?php
$realm = 'Restricted area';
//user => password
$users = array('admin' => 'mypass', 'guest' => 'guest');
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('Text to send if user hits Cancel button');
}
// analyze the PHP_AUTH_DIGEST variable
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
!isset($users[$data['username']]))
die('Wrong Credentials!');
// generate the valid response
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$da
ta['qop'].':'.$A2);
if ($data['response'] != $valid_response)
die('Wrong Credentials!');
// ok, valid username & password
echo 'Your are logged in as: ' . $data['username'];
// function to parse the http auth header
function http_digest_parse($txt)
{
// protect against missing data
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'ur
i'=>1, 'response'=>1);
$data = array();
preg_match_all('@(\w+)=(?:([\'"])([^\2]+)\2|([^\s,]+))@', $txt, $matches, PREG_SET_O
RDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
?>
Compatibility Note: PIease be careIuI when coding the HTTP header Iines. In order to guarantee maximum
compatibiIity with aII cIients, the keyword "Basic" shouId be written with an uppercase "B", the reaIm string
must be encIosed in doubIe (not singIe) quotes, and exactIy one space shouId precede the 401 code in the
HTTP1.0 401 header Iine. Authentication parameters have to be comma-separated as seen in the digest
exampIe above.
Instead oI simpIy printing out PHPAUTHUSER and PHPAUTHPh, as done in the above exampIe, you
may want to check the username and password Ior vaIidity. Perhaps by sending a query to a database, or by
Iooking up the user in a dbm IiIe.
Watch out Ior buggy Internet ExpIorer browsers out there. They seem very picky about the order oI the
headers. Sending the hhh-Authenticate header beIore the HTTP1.0 401 header seems to do the trick Ior
now.
As oI PHP 4.3.0, in order to prevent someone Irom writing a script which reveaIs the password Ior a page that
was authenticated through a traditionaI externaI mechanism, the PHPAUTH variabIes wiII not be set iI
externaI authentication is enabIed Ior that particuIar page and saIe mode is enabIed. RegardIess,
REMOTEUSER can be used to identiIy the externaIIy-authenticated user. So, you can use
SSERJER[REMOTEUSER{.
Configuration Note: PHP uses the presence oI an AuthTvpe directive to determine whether externaI
authentication is in eIIect.
Note, however, that the above does not prevent someone who controIs a non-authenticated URL Irom steaIing
passwords Irom authenticated URLs on the same server.
Both Netscape Navigator and Internet ExpIorer wiII cIear the IocaI browser window's authentication cache Ior
the reaIm upon receiving a server response oI 401. This can eIIectiveIy "Iog out" a user, Iorcing them to re-
enter their username and password. Some peopIe use this to "time out" Iogins, or provide a "Iog-out" button.
Example 35.3. HTTPAuthentication example forcing a new name/password
<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Test Authentication System"');
header('HTTP/1.0 401 Unauthorized');
echo "You must enter a valid login ID and password to access this resource\n";
exit;
}
if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Welcome: {$_SERVER['PHP_AUTH_USER']}<br />";
echo "Old: {$_REQUEST['OldAuth']}";
echo "<form action='{$_SERVER['PHP_SELF']}' METHOD='post'>\n";
echo "<input type='hidden' name='SeenBefore' value='1' />\n";
echo "<input type='hidden' name='OldAuth' value='{$_SERVER['PHP_AUTH_USER']}' />\n";
echo "<input type='submit' value='Re Authenticate' />\n";
echo "</form></p>\n";
}
?>
This behavior is not required by the HTTP Basic authentication standard, so you shouId never depend on this.
Testing with Lynx has shown that Lynx does not cIear the authentication credentiaIs with a 401 server
response, so pressing back and then Iorward again wiII open the resource as Iong as the credentiaI
requirements haven't changed. The user can press the '' key to cIear their authentication inIormation,
however.
AIso note that untiI PHP 4.3.3, HTTPAuthentication did not work using MicrosoIt's IIS server with the CGI
version oI PHP due to a Iimitation oI IIS. In order to get it to work in PHP 4.3.3, you must edit your IIS
conIiguration "Directory Security". CIick on "Edit" and onIy check "Anonymous Access", aII other IieIds
shouId be IeIt unchecked.
Another Iimitation is iI you're using the IIS moduIe (ISAPI) and PHP 4, you may not use the PHPAUTH*
variabIes but instead, the variabIe HTTPAUTHORIZATION is avaiIabIe. For exampIe, consider the IoIIowing
code: list(Suser. Spw) explode(.. base64decode(substr(SSERJER[HTTPAUTHORIZATION{. 6))),
IIS Note:: For HTTP Authentication to work with IIS, the PHP directive cgi.rIc2616headers must be set to 0
(the deIauIt vaIue).
Note: II saIe mode is enabIed, the uid oI the script is added to the realm part oI the hhh-Authenticate
header.
Chapter 36. Cookies
PHP transparentIy supports HTTP cookies. Cookies are a mechanism Ior storing data in the remote browser
and thus tracking or identiIying return users. You can set cookies using the setcookie() or setrawcookie()
Iunction. Cookies are part oI the HTTP header, so setcookie() must be caIIed beIore any output is sent to the
browser. This is the same Iimitation that header() has. You can use the output buIIering Iunctions to deIay the
script output untiI you have decided whether or not to set any cookies or send any headers.
Any cookies sent to you Irom the cIient wiII automaticaIIy be incIuded into a $COOKIE auto-gIobaI array iI
variabIesorder contains "C". II you wish to assign muItipIe vaIues to a singIe cookie, just add [{ to the cookie
name.
Depending on registergIobaIs, reguIar PHP variabIes can be created Irom cookies. However it's not
recommended to reIy on them as this Ieature is oIten turned oII Ior the sake oI security.
SHTTPCOOKIEJARS is aIso set in earIier versions oI PHP when the trackvars conIiguration variabIe is
set. (This setting is aIways on since PHP 4.0.3.)
For more detaiIs, incIuding notes on browser bugs, see the setcookie() and setrawcookie() Iunction.
Chapter 37. Sessions
Session support in PHP consists oI a way to preserve certain data across subsequent accesses. This enabIes
you to buiId more customized appIications and increase the appeaI oI your web site. AII inIormation is in the
Session reIerence section.
Chapter 38. Dealing with XForms
XForms deIines a variation on traditionaI webIorms which aIIows them to be used on a wider variety oI
pIatIorms and browsers or even non-traditionaI media such as PDF documents.
The Iirst key diIIerence in XForms is how the Iorm is sent to the cIient. XForms Ior HTMLAuthors contains
a detaiIed description oI how to create XForms, Ior the purpose oI this tutoriaI we'II onIy be Iooking at a
simpIe exampIe.
Example 38.1. A simple XForms search form
<h:html xmlns:h="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/2002/xforms">
<h:head>
<h:title>Search</h:title>
<model>
<submission action="http://example.com/search"
method="post" id="s"/>
</model>
</h:head>
<h:body>
<h:p>
<input ref="q"><label>Find</label></input>
<submit submission="s"><label>Go</label></submit>
</h:p>
</h:body>
</h:html>
The above Iorm dispIays a text input box (named q), and a submit button. When the submit button is cIicked,
the Iorm wiII be sent to the page reIerred to by action.
Here's where it starts to Iook diIIerent Irom your web appIication's point oI view. In a normaI HTML Iorm, the
data wouId be sent as applicationx-www-form-urlencoded, in the XForms worId however, this inIormation is
sent as XML Iormatted data.
II you're choosing to work with XForms then you probabIy want that data as XML, in that case, Iook in
SHTTPRAhPOSTDATA where you'II Iind the XML document generated by the browser which you can
pass into your Iavorite XSLT engine or document parser.
II you're not interested in Iormatting and just want your data to be Ioaded into the traditionaI SPOST
variabIe, you can instruct the cIient browser to send it as applicationx-www-form-urlencoded by changing the
method attribute to urlencoded-post.
Example 38.2. Using an XForm to populate (@A+.B
<h:html xmlns:h="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/2002/xforms">
<h:head>
<h:title>Search</h:title>
<model>
<submission action="http://example.com/search"
method="urlencoded-post" id="s"/>
</model>
</h:head>
<h:body>
<h:p>
<input ref="q"><label>Find</label></input>
<submit submission="s"><label>Go</label></submit>
</h:p>
</h:body>
</h:html>
Note: As oI this writing, many browsers do not support XForms. Check your browser version iI the above
exampIes IaiIs.
Part VI. Function Reference
I. .NET Functions
Introduction
Warning
This extension is EXPERIMENTAL. The behaviour oI this extension -- incIuding the names oI its Iunctions
and anything eIse documented about this extension -- may change without notice in a Iuture reIease oI PHP.
Use this extension at your own risk.
dotnet_load
(No version inIormation avaiIabIe, might be onIy in CVS)
dotnetIoad Loads a DOTNET moduIe
Description
int dotnet_load ( string $assembly_name |, string $datatype_name |, int $codepage|| )
Warning
This Iunction is EXPERIMENTAL. The behaviour oI this Iunction, the name oI this Iunction, and anything
eIse documented about this Iunction may change without notice in a Iuture reIease oI PHP. Use this Iunction at
your own risk.
Warning
This Iunction is currentIy not documented; onIy the argument Iist is avaiIabIe.
ChangeLog
Version Description
4.1.0 The codepage parameter was added
II. Apache-specific Functions
Introduction
These Iunctions are onIy avaiIabIe when running PHP as an Apache moduIe.
Note: As oI PHP 4.3.2, PATH_TRANSLATED is no Ionger set impIicitIy under the Apache 2 SAPI in contrast to
the situation in Apache 1, where it's set to the same vaIue as the SCRIPT_FILENAME server variabIe when it's
not popuIated by Apache. This change was made to compIy with the CGI speciIication that PATH_TRANSLATED
shouId onIy exist iI PATH_INFO is deIined.
Apache 2 users may use AcceptPathInfo On inside httpd.conf to deIine PATH_INFO.
Installation
For PHP instaIIation on Apache see the instaIIation chapter.
Runtime Configuration
The behaviour oI the Apache PHP moduIe is aIIected by settings in php.ini. ConIiguration settings Irom
php.ini may be overridden by phpIIag settings in the server conIiguration IiIe or IocaI .htaccess IiIes.
Example 206. Turning off PHP parsing for a directory using &"<677#//
php_flag engine off
Table 17. Apache configuration options
Name Default Changeable Changelog
engine "1" PHPINIALL AvaiIabIe since PHP 4.0.5.
chiIdterminate "0" PHPINIALL AvaiIabIe since PHP 4.0.5.
IastmodiIied "0" PHPINIALL AvaiIabIe since PHP 4.0.5.
xbithack "0" PHPINIALL AvaiIabIe since PHP 4.0.5.
For Iurther detaiIs and deIinitions oI the PHPINI* constants, see the Appendix I, php.ini directives.
Here's a short expIanation oI the conIiguration directives.
engine booIean
Turns PHP parsing on or oII. This directive is reaIIy onIy useIuI in the Apache moduIe version oI PHP.
It is used by sites that wouId Iike to turn PHP parsing on and oII on a per-directory or per-virtuaI server
basis. By putting engine off in the appropriate pIaces in the httpd.conf IiIe, PHP can be enabIed or
disabIed.
child_terminate booIean
SpeciIy whether PHP scripts may request chiId process termination on end oI request, see aIso
apachechiIdterminate().
last_modified booIean
Send PHP scripts modiIication date as Last-ModiIied: header Ior this request.
xbithack booIean
Parse IiIes with executabIe bit set as PHP regardIess oI their IiIe ending.
Resource Types
This extension has no resource types deIined.
Predefined Constants
This extension has no constants deIined.
apache_get_modules
(PHP 4 > 4.3.2, PHP 5)
apachegetmoduIes Get a Iist oI Ioaded Apache moduIes
Description
array apache_get_modules ( void )
Get a Iist oI Ioaded Apache moduIes.
Return Values
An array oI Ioaded Apache moduIes.
ChangeLog
Versio
n
Description
5.0.0
Became available when using Apache 1, or the PHP Apache 2 |ilter AP. Before
this time, it was only available when using the Apache 2 handler AP.
Examples
Example 207. apache_get_modules() example
<?php
print_r(apache_get_modules());
?>
The above exampIe wiII output something simiIar to:
Array
(
[0] => core
[1] => http_core
[2] => mod_so
[3] => sapi_apache2
[4] => mod_mime
[5] => mod_rewrite
)
Prev . Apache-specific Functions Next
apache_get_version
(PHP 4 > 4.3.2, PHP 5)
apachegetversion Fetch Apache version
Description
string apache_get_version ( void )
Fetch the Apache version.
Return Values
Returns the Apache version on success, or FALSE on IaiIure.
ChangeLog
Versio
n
Description
4.3.4 Became available with Apache 1.
5.0.0
Became available with the Apache 2
|ilter AP.
Examples
Example 208. apache_get_version() example
<?php
$version = apache_get_version();
echo "$version\n";
?>
The above exampIe wiII output something simiIar to:
Apache/1.3.29 (Unix) PHP/4.3.4
apache_getenv
(PHP 4 > 4.3.0, PHP 5)
apachegetenv Get an Apache subprocessenv variabIe
Description
string apache_getenv ( string $variable |, bool $walk_to_top| )
Get an Apache environment variabIe as speciIied by variable.
This Iunction requires Apache 2 otherwise it's undeIined.
Parameters
variable
The Apache environment variabIe
walk_to_top
Whether to get the top-IeveI variabIe avaiIabIe to aII Apache Iayers.
Return Values
The vaIue oI the Apache environment variabIe on success, or FALSE on IaiIure
Examples
Example 209. apache_getenv() example
The exampIe above shows how to retrieve the vaIue oI the Apache environment variabIe SERJERADDR.
<?php
$ret = apache_getenv("SERVER_ADDR");
echo $ret;
?>
The above exampIe wiII output something simiIar to:
42.24.42.240
apache_lookup_uri
(PHP 4, PHP 5)
apacheIookupuri PerIorm a partiaI request Ior the speciIied URI and return aII inIo about it
Description
ob|ect apache_lookup_uri ( string $filename )
This perIorms a partiaI request Ior a URI. It goes just Iar enough to obtain aII the important inIormation about
the given resource.
This Iunction is onIy supported when PHP is instaIIed as an Apache moduIe.
Parameters
filename
The IiIename (URI) that's being requested.
Return Values
An object oI reIated URI inIormation. The properties oI this object are:
status
the_request
status_line
method
content_typ
e
handler
uri
filename
path_info
args
boundary
no_cache
no_local_co
py
allowed
send_bodyc
t
bytes_sent
byterange
clength
unparsed_ur
i
mtime
request_tim
e
Examples
Example 210. apache_lookup_uri() example
<?php
$info = apache_lookup_uri('index.php?var=value');
print_r($info);
if (file_exists($info->filename)) {
echo 'file exists!';
}
?>
The above exampIe wiII output something simiIar to:
stdClass Object
(
[status] => 200
[the_request] => GET /dir/file.php HTTP/1.1
[method] => GET
[mtime] => 0
[clength] => 0
[chunked] => 0
[content_type] => application/x-httpd-php
[no_cache] => 0
[no_local_copy] => 1
[unparsed_uri] => /dir/index.php?var=value
[uri] => /dir/index.php
[filename] => /home/htdocs/dir/index.php
[args] => var=value
[allowed] => 0
[sent_bodyct] => 0
[bytes_sent] => 0
[request_time] => 1074282764
)
file exists!
apache_note
(PHP 4, PHP 5)
apachenote Get and set apache request notes
Description
string apache_note ( string $note_name |, string $note_value| )
apache_note() is an Apache-speciIic Iunction which gets and sets vaIues in a request's notes tabIe.
Parameters
note_name
The name oI the note.
note_value
The vaIue oI the note.
Return Values
II caIIed with one argument, it returns the current vaIue oI note notename. II caIIed with two arguments, it
sets the vaIue oI note notename to notevalue and returns the previous vaIue oI note notename. II the note
cannot be retrieved, FALSE is returned.
apache_request_headers
(PHP 4 > 4.3.0, PHP 5)
apacherequestheaders Fetch aII HTTP request headers
Description
array apache_request_headers ( void )
Fetches aII HTTP requests Irom the current request.
This Iunction is onIy supported when PHP is instaIIed as an Apache moduIe.
Return Values
An associative array oI aII the HTTP headers in the current request, or FALSE on IaiIure.
Examples
Example 211. apache_request_headers() example
<?php
$headers = apache_request_headers();
foreach ($headers as $header => $value) {
echo "$header: $value <br />\n";
}
?>
The above exampIe wiII output something simiIar to:
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0
Host: www.example.com
Connection: Keep-Alive
Notes
Note: Prior to PHP 4.3.0, apache_request_headers() was caIIed getaIIheaders(). AIter PHP 4.3.0,
getaIIheaders() is an aIias Ior apache_request_headers().
Note: You can aIso get at the vaIue oI the common CGI variabIes by reading them Irom the environment,
which works whether or not you are using PHP as an Apache moduIe. Use phpinIo() to see a Iist oI aII oI the
avaiIabIe environment variabIes.
Note: As oI PHP 4.3.3 you can use this Iunction with the NSAPI server moduIe in Netscape/iPIanet/SunONE
webservers, too.
apache_reset_timeout
(PHP 5 > 5.1.0)
apacheresettimeout Reset the Apache write timer
Description
bool apache_reset_timeout ( void )
apache_reset_timeout() resets the Apache write timer, which deIauIts to 300 seconds. With
settimelimit(0), ignoreuserabort(true) and periodic apache_reset_timeout() caIIs, Apache can
theoreticaIIy run Iorever.
This Iunction requires Apache 1.
Return Values
Returns TRUE on success or FALSE on IaiIure.
Notes
Note: This Iunction is disabIed in saIe mode.
apache_response_headers
(PHP 4 > 4.3.0, PHP 5)
apacheresponseheaders Fetch aII HTTP response headers
Description
array apache_response_headers ( void )
Fetch aII HTTP response headers.
Return Values
An array oI aII Apache response headers on success, or FALSE on IaiIure.
Examples
Example 212. apache_response_headers() example
<?php
print_r(apache_response_headers());
?>
The above exampIe wiII output something simiIar to:
Array
(
[Accept-Ranges] => bytes
[X-Powered-By] => PHP/4.3.8
)
Notes
Note: As oI PHP 4.3.3 you can use this Iunction with the NSAPI server moduIe in Netscape/iPIanet/SunONE
webservers, too.
apache_setenv
(PHP 4 > 4.2.0, PHP 5)
apachesetenv Set an Apache subprocessenv variabIe
Description
bool apache_setenv ( string $variable, string $value |, bool $walk_to_top| )
apache_setenv() sets the vaIue oI the Apache environment variabIe speciIied by variable.
Note: When setting an Apache environment variabIe, the corresponding $SERVER variabIe is not changed.
Parameters
variable
The environment variabIe that's being set.
value
The new variable vaIue.
walk_to_top
Whether to set the top-IeveI variabIe avaiIabIe to aII Apache Iayers.
Return Values
Returns TRUE on success or FALSE on IaiIure.
Examples
Example 213. Setting an Apache environment variable using apache_setenv()
<?php
apache_setenv("EXAMPLE_VAR", "Example Value");
?>
Notes
Note: apache_setenv() can be paired up with apachegetenv() across separate pages or Ior setting variabIes to
pass to Server Side IncIudes (.shtmI) that have been incIuded in PHP scripts.
ascii2ebcdic
(No version inIormation avaiIabIe, might be onIy in CVS)
ascii2ebcdic TransIate string Irom ASCII to EBCDIC
Description
int ascii2ebcdic ( string $ascii_str )
ascii2ebcdic() is an Apache-speciIic Iunction which is avaiIabIe onIy on EBCDIC based operating systems
(OS/390, BS2000). It transIates the ASCII encoded string ascii_str to its equivaIent EBCDIC representation
(binary saIe), and returns the resuIt.
Parameters
ascii_str
The ASCII string that wiII be transIated.
Return Values
The EBCDIC representation oI an ASCII string.
ebcdic2ascii
(No version inIormation avaiIabIe, might be onIy in CVS)
ebcdic2ascii TransIate string Irom EBCDIC to ASCII
Description
int ebcdic2ascii ( string $ebcdic_str )
ebcdic2ascii() is an Apache-speciIic Iunction which is avaiIabIe onIy on EBCDIC based operating systems
(OS/390, BS2000). It transIates the EBCDIC encoded string ebcdic_str to its equivaIent ASCII
representation (binary saIe), and returns the resuIt.
Parameters
ebcdic_str
The EBCDIC string that wiII be transIated.
Return Values
The ASCII representation oI an EBCDIC string.
getallheaders
(PHP 4, PHP 5)
getaIIheaders Fetch aII HTTP request headers
Description
array getallheaders ( void )
Fetches aII HTTP requests Irom the current request.
This Iunction is an aIias Ior apacherequestheaders(). PIease read the apacherequestheaders()
documentation Ior more inIormation on how this Iunction works.
This Iunction is onIy supported when PHP is instaIIed as an Apache moduIe.
Return Values
An associative array oI aII the HTTP headers in the current request, or FALSE on IaiIure.
ChangeLog
Versio
n
Description
4.3.0
Became an alias for apache_request_headers(). Essentially, it was renamed. This
is because this function only works with Apache.
Notes
Note: As oI PHP 4.3.3 you can use this Iunction with the NSAPI server moduIe in Netscape/iPIanet/SunONE
webservers, too.
virtual
(PHP 4, PHP 5)
virtuaI PerIorm an Apache sub-request
Description
bool virtual ( string $filename )
virtual() is an Apache-speciIic Iunction which is simiIar to !--include virtual...-- in modincIude. It
perIorms an Apache sub-request. It is useIuI Ior incIuding CGI scripts or .shtmI IiIes, or anything eIse that you
wouId parse through Apache. Note that Ior a CGI script, the script must generate vaIid CGI headers. At the
minimum that means it must generate a Content-type header.
To run the sub-request, aII buIIers are terminated and IIushed to the browser, pending headers are sent too.
This Iunction is onIy supported when PHP is instaIIed as an Apache moduIe.
Parameters
filename
The IiIe that the virtuaI command wiII be perIormed on.
Return Values
PerIorms the virtuaI command on success, or returns FALSE on IaiIure.
ChangeLog
Versio
n
Description
4.0.6
This function may be used on PHP files. However, it is typically better to use
include() or require() for PHP files.
Notes
Warning
The query string can be passed to the incIuded IiIe but SGET is copied Irom the parent script and onIy
SSERJER[QUERYSTRING{ is IiIIed with the passed query string. The query string may onIy be passed
when using Apache 2. The requested IiIe wiII not be Iisted in the Apache access Iog.
Note: Environment variabIes set in the requested IiIe are not visibIe to the caIIing script.
Note: As oI PHP 4.3.3 you can use this Iunction with the NSAPI server moduIe in Netscape/iPIanet/SunONE
webservers, too.
IV. Advanced PHP debugger
Introduction
APD is the Advanced PHP Debugger. It was written to provide proIiIing and debugging capabiIities Ior PHP
code, as weII as to provide the abiIity to print out a IuII stack backtrace. APD supports interactive debugging,
but by deIauIt it writes data to trace IiIes. It aIso oIIers event based Iogging so that varying IeveIs oI
inIormation (incIuding Iunction caIIs, arguments passed, timings, etc.) can be turned on or oII Ior individuaI
scripts.
Caution
APD is a Zend Extension, modiIying the way the internaIs oI PHP handIe Iunction caIIs, and thus may or may
not be compatibIe with other Zend Extensions (Ior exampIe Zend Optimizer).
Installation
APD is currentIy avaiIabIe as a PECL extension Irom http://pecI.php.net/package/apd. Make sure you have
instaIIed the CGI version oI PHP and it is avaiIabIe in your current path aIong with the phpize script.
Run the IoIIowing command to downIoad, buiId, and instaII the Iatest stabIe version oI APD:
pear install apd
This automaticaIIy instaIIs the APD Zend moduIe into your PHP extensions directory. It is not mandatory to
keep it there; you can store the moduIe in any directory PHP can read as Iong as you set the zendextension
parameter accordingIy.
Windows users can downIoad the extension dII phpapd.dll Irom
http://snaps.php.net/win32/PECLSTABLE/.
In your INI IiIe, add the IoIIowing Iines:
zend_extension = /absolute/path/to/apd.so
apd.dumpdir = /absolute/path/to/trace/directory
apd.statement_tracing = 0
Depending on your PHP buiId, the zendextension directive can be one oI the IoIIowing:
zend_extension (non ZTS, non debug build)
zend_extension_ts ( ZTS, non debug build)
zend_extension_debug (non ZTS, debug build)
zend_extension_debug_ts ( ZTS, debug build)
Building on Win32
To buiId APD under Windows you need a working PHP compiIation environment as described on
http://php.net/ -- basicaIIy, it requires you to have MicrosoIt VisuaI C, win32buiId.zip, bison/IIex, and some
know how to get it to work. AIso ensure that adp.dsp has DOS Iine endings; iI it has unix Iine endings,
MicrosoIt VisuaI C wiII compIain about it.
Runtime Configuration
The behaviour oI these Iunctions is aIIected by settings in php.ini.
Table 19. APD Configuration Options
Name Default Changeable Changelog
apd.dumpdir NULL PHPINIALL
apd.statementtracing "0" PHPINIALL AvaiIabIe since apd 0.9.
For Iurther detaiIs and deIinitions oI the PHPINI* constants, see the Appendix I, php.ini directives.
Here's a short expIanation oI the conIiguration directives.
apd.dumpdir string
Sets the directory in which APD writes proIiIe dump IiIes. You can speciIy an absoIute path or a
reIative path.
You can speciIy a diIIerent directory as an argument to apdsetpproItrace().
apd.statement_tracing booIean
SpecIies whether or not to do per-Iine tracings. Turning this on (1) wiII impact the perIormance oI your
appIication.
Resource Types
This extension has no resource types deIined.
Predefined Constants
The constants beIow are deIined by this extension, and wiII onIy be avaiIabIe when the extension has either
been compiIed into PHP or dynamicaIIy Ioaded at runtime.
Table 20. APD constants
Constant Value Description
FUNCTION_TRACE (integer) 1
ARGS_TRACE (integer) 2
ASSIGNMENT_TRACE (integer) 4
STATEMENT_TRACE (integer) 8
MEMORY_TRACE (integer) 16
TIMING_TRACE (integer) 32
SUMMARY_TRACE (integer) 64
ERROR_TRACE (integer) 128
PROF_TRACE (integer) 256
APD_VERSION (string) exampIe: 1.0.2-dev
How to use PHP-APD in your scripts
1. As the Iirst Iine oI your PHP script, caII the apdsetpproItrace() Iunction to start the trace:
apd_set_pprof_trace();
You can insert the Iine anywhere in your script, but iI you do not start tracing at the beginning oI your
script you discard proIiIe data that might otherwise Iead you to a perIormance bottIeneck.
2. Now run your script. The dump output wiII be written to apd.dumpdirpprofpid.ext.
Tip
II you're running the CGI version oI PHP, you wiII need to add the '-e' IIag to enabIe extended
inIormation Ior apd to work properIy. For exampIe: php -e -f script.php
3. To dispIay Iormatted proIiIe data, issue the pprofp command with the sort and dispIay options oI your
choice. The Iormatted output wiII Iook something Iike:
4.
5. bash-2.05b$ pprofp -R /tmp/pprof.22141.0
6.
7. Trace for /home/dan/testapd.php
8. Total Elapsed Time = 0.00
9. Total System Time = 0.00
10.Total User Time = 0.00
11.
12.
13.Real User System secs/ cumm
14.%Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage
Name
15.----------------------------------------------------------------------------------
----
16.100.0 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0000 0.0009 0 main
17.56.9 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0005 0.0005 0
apd_set_pprof_trace
18.28.0 0.00 0.00 0.00 0.00 0.00 0.00 10 0.0000 0.0000 0
preg_replace
19.14.3 0.00 0.00 0.00 0.00 0.00 0.00 10 0.0000 0.0000 0
str_replace
20.
The -R option used in this exampIe sorts the proIiIe tabIe by the amount oI reaI time the script spent
executing a given Iunction. The "cumm caII" coIumn reveaIs how many times each Iunction was
caIIed, and the "s/caII" coIumn reveaIs how many seconds each caII to the Iunction required, on
average.
21.To generate a caIItree IiIe that you can import into the KCacheGrind proIiIe anaIysis appIication, issue
the pprof2calltree comand.
Contact information
II you have comments, bugIixes, enhancements or want to heIp deveIoping this beast, you can send an maiI to
apdmaiI.communityconnect.com. Any heIp is very weIcome.
apd_breakpoint
(PECL apd:0.2-1.0.1)
apdbreakpoint Stops the interpreter and waits on a CR Irom the socket
Description
bool apd_breakpoint ( int $debug_level )
This can be used to stop the running oI your script, and await responses on the connected socket. To step the
program, just send enter (a bIank Iine), or enter a php command to be executed.
Parameters
debug_level
An integer which is Iormed by adding together the XXXTRACE constants.
It is not recommended to use MEMORY_TRACE. It is very sIow and does not appear to be accurate.
ASSIGNMENT_TRACE is not impIemented yet.
To turn on aII IunctionaI traces (TIMING, FUNCTIONS, ARGS SUMMARY (Iike strace -c)) use the
vaIue 99
Return Values
Returns TRUE on success or FALSE on IaiIure.
Examples
Example 223. Typical session using tcplisten
bash#tcplisten localhost 7777
APD - Advanced PHP Debugger Trace File
---------------------------------------------------------------------------
Process Pid (6118)
Trace Begun at Sun Mar 10 23:13:12 2002
---------------------------------------------------------------------------
( 0.000000): apd_set_session_trace called at /home/alan/Projects/project2/test.
php:5
( 0.074824): apd_set_session_trace_socket() at /home/alan/Projects/project2/tes
t.php:5 returned. Elapsed (0.074824)
( 0.074918): apd_breakpoint() /home/alan/Projects/project2/test.php:7
++ argv[0] $(??) = 9
apd_breakpoint() at /home/alan/Projects/project2/test.php:7 returned. Elapsed (
-2089521468.1073275368)
>\n
statement: /home/alan/Projects/project2/test.php:8
>\n
statement: /home/alan/Projects/project2/test.php:8
>\n
statement: /home/alan/Projects/project2/test.php:10
>apd_echo($i);
EXEC: apd_echo($i);
0
>apd_echo(serialize(apd_get_active_symbols()));
EXEC: apd_echo(serialize(apd_get_active_symbols()));
a:47:{i:0;s:4:"PWD";i:1;s:10:"COLORFGBG";i:2;s:11:"XAUTHORITY";i:3;s:14:"
COLORTERM_BCE";i:4;s:9:"WINDOWID";i:5;s:14:"ETERM_VERSION";i:6;s:16:"SE
SSION_MANAGER";i:7;s:4:"PS1";i:8;s:11:"GDMSESSION";i:9;s:5:"USER";i:10;s:5:"
MAIL";i:11;s:7:"OLDPWD";i:12;s:5:"LANG";i:13;s:10:"COLORTERM";i:14;s:8:"DISP
LAY";i:15;s:8:"LOGNAME";i:16;s:6:"
>apd_echo(system('ls /home/mydir'));
........
>apd_continue(0);
apd_callstack
(PECL apd:0.2-0.4)
apdcaIIstack Returns the current caII stack as an array
Description
array apd_callstack ( void )
Returns the current caII stack as an array
Return Values
An array containing the current caII stack.
Examples
Example 224. apd_callstack() example
<?php
print_r(apd_callstack());
?>
apd_clunk
(No version inIormation avaiIabIe, might be onIy in CVS)
apdcIunk Throw a warning and a caIIstack
Description
void apd_clunk ( string $warning |, string $delimiter| )
Behaves Iike perI's Carp::cIuck. Throw a warning and a caIIstack.
Parameters
warning
The warning to throw.
delimiter
The deIimiter. DeIauIt to BR .
Return Values
No vaIue is returned.
Examples
Example 225. apd_clunk() example
<?php
apd_clunk("Some Warning", "<br/>");
?>
apd_continue
(PECL apd:0.2-1.0.1)
apdcontinue Restarts the interpreter
Description
bool apd_continue ( int $debug_level )
UsuaIIy sent via the socket to restart the interpreter.
Parameters
debug_level
An integer which is Iormed by adding together the XXXTRACE constants.
It is not recommended to use MEMORY_TRACE. It is very sIow and does not appear to be accurate.
ASSIGNMENT_TRACE is not impIemented yet.
To turn on aII IunctionaI traces (TIMING, FUNCTIONS, ARGS SUMMARY (Iike strace -c)) use the
vaIue 99
Return Values
Returns TRUE on success or FALSE on IaiIure.
Examples
Example 226. apd_continue() example
<?php
apd_continue(0);
?>
apd_croak
(PECL apd:0.2-0.4)
apdcroak Throw an error, a caIIstack and then exit
Description
void apd_croak ( string $warning |, string $delimiter| )
Behaves Iike perI's Carp::croak. Throw an error, a caIIstack and then exit.
Parameters
warning
The warning to throw.
delimiter
The deIimiter. DeIauIt to BR .
Return Values
No vaIue is returned.
Examples
Example 227. apd_croak() example
<?php
apd_croak("Some Warning","<P>");
?>
apd_dump_function_table
(No version inIormation avaiIabIe, might be onIy in CVS)
apddumpIunctiontabIe Outputs the current Iunction tabIe
Description
void apd_dump_function_table ( void )
Outputs the current Iunction tabIe.
Return Values
No vaIue is returned.
Examples
Example 228. apd_dump_function_table() example
<?php
apd_dump_function_table();
?>
apd_dump_persistent_resources
(PECL apd:0.2-0.4)
apddumppersistentresources Return aII persistent resources as an array
Description
array apd_dump_persistent_resources ( void )
Return aII persistent resources as an array.
Return Values
An array containing the current caII stack.
Examples
Example 229. apd_dump_persistent_resources() example
<?php
print_r(apd_dump_persistent_resources());
?>
apd_dump_regular_resources
(PECL apd:0.2-0.4)
apddumpreguIarresources Return aII current reguIar resources as an array
Description
array apd_dump_regular_resources ( void )
Return aII current reguIar resources as an array.
Return Values
An array containing the current reguIar resources.
Examples
Example 230. apd_dump_regular_resources() example
<?php
print_r(apd_dump_regular_resources());
?>
apd_echo
(PECL apd:0.2-1.0.1)
apdecho Echo to the debugging socket
Description
bool apd_echo ( string $output )
UsuaIIy sent via the socket to request inIormation about the running script.
Parameters
output
The debugged variabIe.
Return Values
Returns TRUE on success or FALSE on IaiIure.
Examples
Example 231. apd_echo() example
<?php
apd_echo($i);
?>
apd_get_active_symbols
(PECL apd:0.2)
apdgetactivesymboIs Get an array oI the current variabIes names in the IocaI scope
Description
array apd_get_active_symbols ( void )
Returns the names oI aII the variabIes deIined in the active scope, (not their vaIues).
Return Values
A muItidimensionaI array with aII the variabIes.
Examples
Example 232. apd_get_active_symbols() example
<?php
apd_echo(apd_get_active_symbols());
?>
apd_set_pprof_trace
(PECL apd:0.2-1.0.1)
apdsetpproItrace Starts the session debugging
Description
string apd_set_pprof_trace ( |string $dump_directory |, string $fragment|| )
Starts debugging to pprof{processid} in the dump directory.
Parameters
dump_directory
The directory in which the proIiIe dump IiIe is written. II not set, the apd.dumpdir setting Irom the
php.ini IiIe is used.
fragment
Return Values
Returns path oI the destination IiIe.
Examples
Example 233. apd_set_pprof_trace() example
<?php
apd_set_pprof_trace();
?>
apd_set_session_trace
(PECL apd:0.2-0.4)
apdsetsessiontrace Starts the session debugging
Description
void apd_set_session_trace ( int $debug_level |, string $dump_directory| )
Starts debugging to apddump{processid} in the dump directory.
Parameters
debug_level
An integer which is Iormed by adding together the XXXTRACE constants.
It is not recommended to use MEMORY_TRACE. It is very sIow and does not appear to be accurate.
ASSIGNMENT_TRACE is not impIemented yet.
To turn on aII IunctionaI traces (TIMING, FUNCTIONS, ARGS SUMMARY (Iike strace -c)) use the
vaIue 99
dump_directory
The directory in which the proIiIe dump IiIe is written. II not set, the apd.dumpdir setting Irom the
php.ini IiIe is used.
Return Values
No vaIue is returned.
Examples
Example 234. apd_set_session_trace() example
<?php
apd_set_session_trace(99);
?>
apd_set_session
(PECL apd:0.2-0.4)
apdsetsession Changes or sets the current debugging IeveI
Description
void apd_set_session ( int $debug_level )
This can be used to increase or decrease debugging in a diIIerent area oI your appIication.
Parameters
debug_level
An integer which is Iormed by adding together the XXXTRACE constants.
It is not recommended to use MEMORY_TRACE. It is very sIow and does not appear to be accurate.
ASSIGNMENT_TRACE is not impIemented yet.
To turn on aII IunctionaI traces (TIMING, FUNCTIONS, ARGS SUMMARY (Iike strace -c)) use the
vaIue 99
Return Values
No vaIue is returned.
Examples
Example 235. apd_set_session() example
<?php
apd_set_session(9);
?>
apd_set_socket_session_trace
(No version inIormation avaiIabIe, might be onIy in CVS)
apdsetsocketsessiontrace Starts the remote session debugging
Description
bool apd_set_socket_session_trace ( string $tcp_server, int $socket_type, int $port,
int $debug_level )
Connects to the speciIied tcp_server (eg. tcpIisten) and sends debugging data to the socket.
Parameters
tcp_server
IP or Unix Domain socket (Iike a IiIe) oI the TCP server.
socket_type
Can be AF_UNIX Ior IiIe based sockets or APD_AF_INET Ior standard tcp/ip.
port
You can use any port, but higher numbers are better as most oI the Iower numbers may be used by
other system services.
debug_level
An integer which is Iormed by adding together the XXXTRACE constants.
It is not recommended to use MEMORY_TRACE. It is very sIow and does not appear to be accurate.
ASSIGNMENT_TRACE is not impIemented yet.
To turn on aII IunctionaI traces (TIMING, FUNCTIONS, ARGS SUMMARY (Iike strace -c)) use the
vaIue 99
Return Values
Returns TRUE on success or FALSE on IaiIure.
Examples
Example 236. apd_set_socket_session_trace() example
<?php
apd_set_socket_session_trace("127.0.0.1",APD_AF_INET,7112,0);
?>
override_function
(PECL apd:0.2-1.0.1)
overrideIunction Overrides buiIt-in Iunctions
Description
bool override_function ( string $function_name, string $function_args, string
$function_code )
Overrides buiIt-in Iunctions by repIacing them in the symboI tabIe.
Parameters
function_name
The Iunction to override.
function_args
The Iunction arguments, as a coma separated string.
UsuaIIy you wiII want to pass this parameter, as weII as the function_code parameter, as a singIe
quote deIimited string. The reason Ior using singIe quoted strings, is to protect the variabIe names Irom
parsing, otherwise, iI you use doubIe quotes there wiII be a need to escape the variabIe names, e.g.
\Svourvar.
function_code
The new code Ior the Iunction.
Return Values
Returns TRUE on success or FALSE on IaiIure.
Examples
Example 237. override_function() example
<?php
override_function('test', '$a,$b', 'echo "DOING TEST"; return $a * $b;');
?>
rename_function
(PECL apd:0.2-1.0.1)
renameIunction Renames origname to newname in the gIobaI Iunction tabIe
Description
bool rename_function ( string $original_name, string $new_name )
Renames a origname to newname in the gIobaI Iunction tabIe. UseIuI Ior temporariIy overriding buiIt-in
Iunctions.
Parameters
original_name
The originaI Iunction name.
new_name
The new name Ior the original_name Iunction.
Return Values
Returns TRUE on success or FALSE on IaiIure.
Examples
Example 238. rename_function() example
<?php
rename_function('mysql_connect', 'debug_mysql_connect' );
?>
V. Array Functions
Introduction
These Iunctions aIIow you to interact with and manipuIate arrays in various ways. Arrays are essentiaI Ior
storing, managing, and operating on sets oI variabIes.
SimpIe and muIti-dimensionaI arrays are supported, and may be either user created or created by another
Iunction. There are speciIic database handIing Iunctions Ior popuIating arrays Irom database queries, and
severaI Iunctions return arrays.
PIease see the Arrays section oI the manuaI Ior a detaiIed expIanation oI how arrays are impIemented and
used in PHP. See aIso Array operators Ior other ways how to manipuIate the arrays.
Requirements
No externaI Iibraries are needed to buiId this extension.
Installation
There is no instaIIation needed to use these Iunctions; they are part oI the PHP core.
Runtime Configuration
This extension has no conIiguration directives deIined in php.ini.
Resource Types
This extension has no resource types deIined.
Predefined Constants
The constants beIow are aIways avaiIabIe as part oI the PHP core.
CASE_LOWER (integer)
CASE_LOWER is used with arraychangekeycase() and is used to convert array keys to Iower case.
This is aIso the deIauIt case Ior arraychangekeycase().
CASE_UPPER (integer)
CASE_UPPER is used with arraychangekeycase() and is used to convert array keys to upper case.
Sorting order IIags:
SORT_ASC (integer)
SORT_ASC is used with arraymuItisort() to sort in ascending order.
SORT_DESC (integer)
SORT_DESC is used with arraymuItisort() to sort in descending order.
Sorting type IIags: used by various sort Iunctions
SORT_REGULAR (integer)
SORT_REGULAR is used to compare items normaIIy.
SORT_NUMERIC (integer)
SORT_NUMERIC is used to compare items numericaIIy.
SORT_STRING (integer)
SORT_STRING is used to compare items as strings.
SORT_LOCALE_STRING (integer)
SORT_LOCALE_STRING is used to compare items as strings, based on the current IocaIe. Added in PHP
4.4.0 and 5.0.2.
COUNT_NORMAL (integer)
COUNT_RECURSIVE (integer)
EXTR_OVERWRITE (integer)
EXTR_SKIP (integer)
EXTR_PREFIX_SAME (integer)
EXTR_PREFIX_ALL (integer)
EXTR_PREFIX_INVALID (integer)
EXTR_PREFIX_IF_EXISTS (integer)
EXTR_IF_EXISTS (integer)
EXTR_REFS (integer)