Tải bản đầy đủ (.pdf) (69 trang)

Tài liệu Introduction to Version Contron with CVS doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.94 MB, 69 trang )

VOLUME II - ISSUE 11
php
|
Cruise
March 1
st
- March 5
th
2004
See inside for details
Get Ready For
www.phparch.com
NOVEMBER 2003
Plus:
Tips & Tricks, Book Reviews, Product Reviews and much
Introduction to Version Introduction to Version
Control withControl with
Discover the power of collaborationDiscover the power of collaboration
CVSCVS
Implementing Web ServerImplementing Web Server
Load ManagementLoad Management
Preventing resource overloads
Working with PEAR::XML_SerializerWorking with PEAR::XML_Serializer
XML has never been so easy
Introduction to PHP-GTKIntroduction to PHP-GTK
Getting started with desktop applications in PHP
An Introduction to SQLiteAn Introduction to SQLite
SQL for the masses
Object Overloading in PHPObject Overloading in PHP

Visit us at www


.php
arch.com/cruise for more details.
php
|
Cruise
March 1
st
- March 5
th
2004
Andrei Zmievski -
Andrei's Regex Clinic
, James Cox -
XML for the Masses
,
Wez Furlong -
Extending PHP
, Stuart Herbert
- Safe and Advanced Error Handling
in PHP5, Peter James - mod_rewrite: From Zero to Hero, George Schlossnagle -
Profiling PHP, Ilia Alshanetsky - Programming Web Services, John Coggeshall -
Mastering PDFLib, Jason Sweat - Data Caching Techniques
<?
?>
We’ve got you covered,
from port to sockets.
Port Canaveral • Coco Cay • Nassau
Plus: Stream socket programming, debugging techniques, writing high-performance code,
data mining, PHP 101, safe and advanced error handling in PHP5, programming smarty,
and much, much more!

In partnership with Zend
Technologies
Zend Studio 3.0 is the
official PHP IDE of
php|cruise
Features
php
|
Cruise
Traditional PHP
Conference*
Conference Pass
$ 899.99
**
$ 1,150.00
Hotel
Included
($ 400.00)
Meals
Included***
($ 200.00)
Totals:
$ 899.99
$1,750.00
You Save $ 850
* Based on average of two major PHP conferences
** Based on interior stateroom, double occupancy
*** Alcohol and carbonated beverages not included
ENJOY LEARNING PHP IN A FUN AND EXCITING
ENVIRONMENT—AND SAVE A BUNDLE!

6
Editorial
7
What’s New!
40
Product Review
PHPEclipse
by Eddie Peloke
58
Product Review
PhpED 3.2.1
by Marco Tabini
61
Tips & Tricks
By John W. Holmes
65
Book Reviews
by Peter MacIntyre
67
Bits & Pieces
Real. Interesting. Stuff.
by Peter James
69
e x i t ( 0 ) ;
Frequently Annoying Questions
By Marco Tabini
9
Object Overloading in PHP
by Alessandro Sfondrini
15

Introduction to Version Control with
CVS
by Dejan Bosanac
25
Introduction to PHP-GTK
by Eric Persson
30
Speaker on the High Seas
An Interview with Wez Furlong
33
An Introduction to SQLite
by John Coggeshall
44
Working with PEAR::XML_Serializer
by Stephan Schmidt
52
Implementing Web Server Load
Management
by Rodrigo Becke Cabral
3
November 2003

PHP Architect

www.phparch.com
TABLE OF CONTENTS
II NN DD EE XX
II NN DD EE XX
php|architect
Features

Departments
Existing
subscribers
can upgrade to
the Print edition
and save!
Login to your account
for more details.
NEW!
NEW!
*By signing this order form, you agree that we will charge your account in Canadian
dollars for the “CAD” amounts indicated above. Because of fluctuations in the
exchange rates, the actual amount charged in your currency on your credit card
statement may vary slightly.
**Offer available only in conjunction with the purchase of a print subscription.
Choose a Subscription type:
Canada/USA $ 97.99 CAD ($69.99 US*)
International Surface $111.99 CAD ($79.99 US*)
International Air $125.99 CAD ($89.99 US*)
Combo edition $ 14.00 CAD ($10.00 US)
(print + PDF edition)
Your charge will appear under the name "Marco Tabini & Associates, Inc." Please
allow up to 4 to 6 weeks for your subscription to be established and your first issue
to be mailed to you.
*US Pricing is approximate and for illustration purposes only.
php|architect Subscription Dept.
P.O. Box 3342
Markham, ON L3R 9Z4
Canada
Name: ____________________________________________

Address: _________________________________________
City: _____________________________________________
State/Province: ____________________________________
ZIP/Postal Code: ___________________________________
Country: ___________________________________________
Payment type:
VISA Mastercard American Express
Credit Card Number:________________________________
Expiration Date: _____________________________________
E-mail address: ______________________________________
Phone Number: ____________________________________
Visit: for
more information or to subscribe online.
Signature: Date:
To subscribe via snail mail - please detach/copy this form, fill it
out and mail to the address above or fax to +1-416-630-5057
php|architect
The Magazine For PHP Professionals
November 2003

PHP Architect

www.phparch.com
EE DD II TT OO RR II AA LL RR AA NN TT SS
EE DD II TT OO RR II AA LL RR AA NN TT SS
php|architect
Volume II - Issue 11
November, 2003
Publisher
Marco Tabini

Editor-in-Chief
Peter James

Editor-at-Large
Brian K. Jones

Editorial Team
Arbi Arzoumani
Peter James
Peter MacIntyre
Brian Jones
Eddie Peloke
Graphics & Layout
Arbi Arzoumani
Managing Editor
Emanuela Corso
Director of Marketing
J. Scott Johnson

Account Executive
Shelley Johnston

Authors
Dejan Bosanac, Rodrigo Becke Cabral, John Coggeshall,
Eric Persson, Alessandro Sfondrini, Stephan Schmidt
php|architect (ISSN 1705-1142) is published twelve times a year by Marco Tabini &
Associates, Inc., P.O. Box 54526, 1771 Avenue Road, Toronto, ON M5M 4N5, Canada.
Although all possible care has been placed in assuring the accuracy of the contents of this
magazine, including all associated source code, listings and figures, the publisher assumes
no responsibilities with regards of use of the information contained herein or in all asso-

ciated material.
Contact Information:
General mailbox:
Editorial:
Subscriptions:
Sales & advertising:
Technical support:
Copyright © 2002-2003 Marco Tabini & Associates, Inc.
— All Rights Reserved
I
like to consider myself a fairly adept PHP
developer. I’ve been using PHP for just over
two years continuously (plus massive
amounts of overtime and hobby develop-
ment), and have made some pretty cool
applications (IMO, at least). Even so, I have
yet to actually touch the vast majority of PHP
extensions. And those are just the ones doc-
umented on
www.php.net
. Countless others
have been developed that may never be pro-
filed there.
This leads me to my point. Often, the arti-
cle ideas submitted to us at php|a deal with
aspects of PHP development that we know lit-
tle about. As technical editors, though, it is
our job to ensure that the material presented
here is as accurate as possible, which forces us
to (as much as possible) fully understand and

grasp the technology being discussed. This
presents incredible opportunities for learning
and growth.
I really think that there are stages in knowl-
edge. When you first start out learning some-
thing, you are ignorant and you (usually)
make no bones about it. As your knowledge
grows, you can quickly and easily become
cocky and arrogant. This cocky and arrogant
attitude usually succeeds giving you plenty of
humble pie to eat, which manages to eventu-
ally settle you into the comfortable stage
where you know what you’re doing, but
aren’t going to make a big deal out of it.
When I look back at the time I’ve been at
php|a, and the articles I’ve worked with, I’m
astonished at how much I’ve learned. When I
started at php|a, I was definitely in the “armed
and dangerous” camp. I knew it all. After a
number of months working with some of
PHP’s best and brightest, I now realize that I
know nothing, and should just shut up.
It’s unfortunate, therefore, that I must leave
php|a. I’ve really enjoyed working with every-
body here, as well as you readers. You’re the
reason we burn the midnight oil bringing you
the best that the community has to offer
every month. Your feedback and comments
every month help us create a better publica-
EDITORIAL

tion... one that we can all be proud of. Many of our readers are also our authors, and I’ve very
much enjoyed working with you as well. Your seemingly limitless practical knowledge of PHP
has brought much enlightenment to the team here, and we thank you for that, as well as for
the excellent articles that you offer us.
Of course, php|a will continue. I mean, where would it go? Brian Jones will return as “Guest
Editor-in-Chief” for the December issue, which is our first anniversary and will feature some of
the best content yet (of course!), and our own Marco Tabini will do the honours again starting
with January. Good luck Marco!
Until then...
November 2003

PHP Architect

www.phparch.com
6
EDITORIAL
php|a
PHP.net announced the release of PHP
4.3.4.
The latest version of the 4.0 branch of PHP, 4.3.4, has
been released to the public. It contains, among other
things, these fixes, additions and improvements:
• Fixed
disk_total_space()
and
disk_free_space()
under FreeBSD.
• Fixed FastCGI support on Win32.
• Fixed FastCGI being unable to bind to a specific
IP.

• Fixed several bugs in
mail()
implementation
on win32.
• Fixed crashes in a number of functions.
• Fixed compile failure on MacOSX 10.3 Panther.
• Over 60 bug fixes
For more information, visit
www.php.net
.
PEAR 1.3b3
PEAR has released of the PEAR Base system.
The PEAR package contains:
• the PEAR base class
• the PEAR_Error error handling mechanism
• the PEAR installer, for creating, distributing
and installing packages
• the OS_Guess class for retrieving info about
the OS where PHP is running on
What’s New!
NEW STUFF
NEW STUFF
PHP 5.0.0 Beta 2
Can’t wait until PHP5? Well,
we are one step closer with
the latest Beta 2 release of the
new version of PHP.
PHP.net
announced: ”This is the first feature
complete version of PHP 5, and we recommend for

PHP users to try it. PHP 5 is still not ready for pro-
duction use!
Some of the more major changes include:
• PHP 5 features the Zend Engine 2.
• XML support has been completely redone in
PHP 5, all extensions are now focused
around the excellent libxml2 library
(
/>).
• SQLite has been bundled with PHP. For
more information on SQLite, please visit
their website.
• A new SimpleXML extension for easily
accessing and manipulating XML as PHP
objects. It can also interface with the DOM
extension and vice-versa.
• Streams have been greatly improved,
including the ability to access low-level
socket operations on streams.
There have been many changes since Beta 1,
some of them documented in the NEWS file and
most language changes are documented in
ZEND_CHANGES “
November 2003

PHP Architect

www.phparch.com
7
• the System class for quick handling common

operations with files and directories
Changes in this release include changes to the PEAR
installer.
Get a taste of the new PEAR at
PEAR.PHP.net
PhpDocumentor 1.2.3
phpDocumentor is a JavaDoc-like automatic documen-
tation generator for PHP written in PHP.
The phpDocumentor team announces:
“The phpDocumentor team is pleased to announce
the release of phpDocumentor 1.2.3.
This is a bugfix maintenance release. Only a few small
bugs have been found and fixed.
Notice: PEAR users will want to read the release notes
for directions on how to automatically setup the web inter-
face on install”
Get all the files and more information from the pro-
ject’s Sourceforge page at:
/>PHP2Go
Sourceforge.net
announces the release of PHP2Go, a
web development framework.
The release announces: “After 12 months of develop-
ment, we are very proud to announce that the first beta
version of PHP2Go Web Development Framework was
released. We strongly recommend that you don’t use this
first beta version in a production environment. Soon, the
first stable releases will be available here or at the project
area in SourceForge.net.
In this development period, almost 100 classes were cre-

ated and tested. Almost all common features needed by a
small, medium or high web application were included in
the framework. However, the documentation of this first
release is still poor. In a huge framework, that may be used
to act like a basement to the development of one or more
applications, documentation, tutorials and help stuff are
very important. Because of that, as the time goes by, the
complete instructions on how to build simple or complex
stuff for your Web applications using PHP2Go will be avail-
able here.
For now, we suggest that you make your first experience
with PHP2Go. Bug reports, suggestions or any doubts will
be very welcome.”
Get more information or download from
Sourceforge.net
at:
/>:object::kitchen R4
Objectkitchen announces release number 4.
What is it?
Objectkitchen is a Java application used through a
client/server-style connection from your application. It
was written with the following goals in mind.
It should be very easy to use. An average program-
mer should be able to start storing and retrieving object
data within 15 minutes of installation.
NNEEWW SSTTUUFFFF
MySQL.com announces the release of MySQL version 4.0.16.
Some changes mentioned in the changelog include:
• Added the following new server variables to allow more precise memory allocation:
rraannggee__aalllloocc__bblloocckk__ssiizzee

,
qquueerryy__aalllloocc__bblloocckk__ssiizzee
,
qquueerryy__pprreeaalllloocc__ssiizzee
,
ttrraannssaaccttiioonn__aalllloocc__bblloocckk__ssiizzee
, and
ttrraannssaaccttiioonn__pprreeaalllloocc__ssiizzee
.

mmyyssqqllbbiinnlloogg
now reads options files. To make this work one must now specify
——rreeaadd--ffrroomm--rreemmoottee--sseerrvveerr
when reading binary logs from a MySQL server. (Note that using a remote server is deprecated and may
disappear in future
mmyyssqqllbbiinnlloogg
versions).
• Block
SSIIGGPPIIPPEE
also for non-threaded programs. The blocking is moved from
mysql_init()
to
mysql_server_init()
, which is automatically called on the first call to
mysql_init()
.
• Added
——lliibbss__rr
and
——iinncclluuddee

options to
mmyyssqqll__ccoonnffiigg
.
• New
``>>
prompt for mysql. This prompt is similar to the
‘‘>>
and
““>>
prompts, but indicates that an identifi-
er quoted with backticks was begun on an earlier line and the closing backtick has not yet been seen.
Get more information or download from
MySQL.com
.
November 2003

PHP Architect

www.phparch.com
8
It should be usable from a multitude of languages,
but with primary focus on PHP and Java.
It should provide natural mapping of an object-ori-
ented design. Relations between objects should just
work without any extra work.
It should fast enough to be usable for reasonably
busy websites.
The best way to discover what objectkitchen is actu-
ally about is to read the language introduction. Its a
small one-page document, which provides you with an

easy to read example using PHP as the client language.
Get more information from:
Objectkitchen.narcissisme.dk.
ADOdb 4.00
PHPeverywhere announces the release of ADOdb 4.00
The release announces: ”ADOdb 4.00 is out after a 3
month beta testing process.
The distinguishing feature of this release is the perform-
ance monitoring functionality. AFAIK, it is the first Open
Source cross-platform, multi-database performance moni-
toring and health check software in the world.
It features:
• A quick health check of your database server
using
$$ppeerrff-->>HHeeaalltthhCChheecckk(())
or
$$
ppeerrff--
>>HHeeaalltthhCChheecckkCCLLII(())
.
• User interface for performance monitoring,
$$ppeerrff--
>>UUII(())
. This UI displays:
- the health check,
- all SQL logged and their query plans,
- a list of all tables in the current database
- an interface to continiously poll the server
for key performance indicators such as CPU,
Hit Ratio, Disk I/O

• Gives you an API to build database monitoring
tools for a server farm, for example calling
$$ppeerrff--
>>DDBBPPaarraammeetteerr((‘‘ddaattaa ccaacchhee hhiitt rraattiioo’’))
returns this
very important statistic in a database indepen-
dant manner. “
Get more information from PHPEverywhere at:
/>PHP Meeting in Paris
The French PHP User Group AFUP association is proud
to announce the third annual PHP meeting in Paris, on
November 26th and 27th, 2003.
What is it?
Developers and managers will gather to meet Zeev
Suraski and other prominent community experts for
two days of conferences, packed with solutions and
advanced techniques.
Get more information from:
AFUP.org
php|a
NNEEWW SSTTUUFFFF
PHP-GTK 1.0.0
PHP-GTK announces the release of version 1.0.0.
What is it?
PHP-GTK is an extension for PHP programming lan-
guage that implements language bindings for GTK+
toolkit. It provides an object-oriented interface to
GTK+ classes and functions and greatly simplifies
writing client side cross-platform GUI applications.
The release announces: “PHP-GTK Version 1.0.0

is finally out after almost a year of being in stasis.
This is probably the last major version that will
work with PHP 4 and Gtk+ 1.x. There might be
more bugfixes, but no new features or upgrades
will be implemented. PHP-GTK 2 is under develop-
ment and will focus on PHP 5 and Gtk+ 2.x. “
Get more information from
GTK.PHP.net
.
Direction|PHP
NEXEN.NET
, leading portal for PHP/MySQL plat-
form in French, and php|architect, the Magazine
for PHP Professionals, have announced the imme-
diate availability of DIRECTION|PHP, the French
monthly magazine for PHP/MySQL professionals.
”The French PHP community is among the
largest and the most advanced in the world.”, says
Damien Seguy, editor-in-chief of Direction|PHP. “
It needed a resource of expert knowledge and in-
depth coverage of the industry. Naturally, that led
us to partner with php|architect. “.
php|architect provides a monthly technical
resource for PHP professionals in the English mar-
ket that includes in-depth articles, news, editorial
comment, and product and book reviews.
Direction|PHP is focused tightly on covering French
news, and licenses part of its content from
php|architect.
” Most technical knowledge is available in

English, even if its authors are not native English
speakers. I believe Direction|PHP will create oppor-
tunities for both French authors and companies to
step up to the plate and shine “, adds Damien
Seguy.
Get more information about Direction|PHP, visit
their homepage.
What is overloading?
Overloading is an important feature of most Object
Oriented Programming (OOP) languages like Java and
C++. In these languages, overloading allows the pro-
grammer to declare many methods or properties with
the same name. Which one will be used when a call to
that function name is made depends on the type (inte-
ger, string, etc.) and the number of arguments passed
to the method.
If you aren’t too familiar with OO languages, maybe
a very basic example in Java will help you out. Take a
look at Listing 1.
When the Java Virtual Machine finds a call to method
hheelllloo(())
of class Greet in this code, it will choose the
right method depending on the number of arguments.
Of course, if we try to do this in PHP, all we will obtain
is a fatal error, like so:
Fatal Error: Cannot redeclare hello()
For a strongly-typed language, overloading is impor-
tant because it allows methods to behave in different
ways depending on the number and type of the argu-
ments received. If we overload the constructor of a

class, we can obtain different objects depending on the
number and type of parameters passed.
Overloading is one of the most useful peculiarities of
OO languages. Unfortunately (at least, in my humble
opinion), PHP wasn’t born to be object-oriented. OOP
is only really supported since PHP4, but still in quite a
poor way. Thankfully, many improvements are being
introduced, and PHP 5 will finally provide great OOP
support. One of these improvements is the overloading
extension. Although this extension differs from the Java
version of overloading, we’ll show how to use it to sim-
ulate that overloading in PHP.
What is overloading in PHP?
The “Object property and method call overloading”
extension was introduced as a built-in, experimental
extension in PHP 4.3.0. It is supposed to become sta-
ble in PHP 5.
Its purpose is something different from the overload-
ing present in most object-oriented languages. In fact it
November 2003

PHP Architect

www.phparch.com
9
FEA
FEA
TURE
TURE
Object Overloading in PHP

by Alessandro Sfondrini
PHP: 4.3.3+
OS: N/A
Applications: MySQL 4.0.12, Apache 1.3.27
Code:
/>Code Directory: object-overloading
REQUIREMENTS
class Greet {
hello() {
System.out.println(“Hello World”);
}
hello(string name) {
System.out.println(“Hello “ + name);
}
hello(string name, string from) {
System.out.println(“Hello “ + name);
System.out.println(“Greetings from “ + from);
}
}
LISTING 1: Basic OO example in JAVA
doesn’t even allow you to redeclare a method. Instead,
its purpose is to allow you to use methods (and proper-
ties) which haven’t ever been declared inside the class.
It does this by offering up three special methods that
will be executed when an attempt is made to access a
method or property that doesn’t exist. These “magic”
methods are listed below.
____ggeett(())
: called when trying to use the value of
undefined properties

____sseett(())
: called when trying to set the value of
undefined properties
____ccaallll(())
: called when accessing undefined methods.
The most useful of these three methods to us is
____ccaallll(())
, since you’ve always been “allowed” to set and
get undefined properties in PHP 4. Among other
things,
____ccaallll(())
allows us to execute built-in PHP func-
tions or user-defined functions as if they were actually
methods of the class.
Overloading properties:
____ggeett(())
and
____sseett(())
To get the value of an undefined property, we must use
____ggeett(())
.
boolean __get([string property_name], [mixed
return_value])
The property_name parameter is the name of the
undefined property being accessed, and the
return_value parameter is the value we will set inside
the function. return_value should be passed by refer-
ence (using the special character “&”) to allow
____ggeett(())
to set the value. Listing 2 shows how the

____ggeett(())
method works.
First, we set the
$$ggrreeeett
property. This is the only prop-
erty of class TryGet that we can access without over-
loading the class.
Next, we have to fill in the
____ggeett(())
method with the
logic to determine what value (
$$PPrrooppVVaalluuee
) should be
returned for an undefined property (
$$PPrrooppNNaammee
). In this
case we set
$$PPrrooppVVaalluuee
to an error message
(“$PropName isn’t defined”), but we could also set it to
FALSE, to zero, to a blank string, or to whatever makes
sense.
Finally, we return TRUE from
____ggeett(())
. This is because
all of the “magic” methods should only return TRUE or
FALSE. This tells the parser whether the access was suc-
cessful—returning FALSE will make the parser display a
notice (“Notice: Undefined property”).
Before we can test this class, we must overload it

using the
oovveerrllooaadd(())
function.
void overload(string ClassName)
Lastly, we try to print a defined property (
$$ggrreeeett
) and
two undefined ones (
$$ffoooo
and
$$bbaarr
). The output is as
follows:
Hello World!
foo isn’t defined
bar isn’t defined
This way we never display the notice; we could also
decide to return TRUE only for some properties and dis-
play the notice for the others, using an if-else control (if
the property is allowed return TRUE, else return FALSE).
To set an undefined property we must use
____sseett(())
.
boolean __set([string property_name], [mixed
value_to_assign])
This “magic” method must be used together with
____ggeett(())
in order to work—setting a property without
being able to get it is useless. Have a look at Listing 3
for an example.

The
____sseett(())
method stores the value of the undefined
property that the user tried to set into an associative
array (
$$eelleemm
), and then returns TRUE. Like for
____ggeett(())
,
returning FALSE will cause a notice.
Next, we put an if-else control in method
____ggeett(())
. If
the undefined property is stored in the
$$eelleemm
array, we’ll
set
$$PPrrooppVVaalluuee
to that value, otherwise set the value to
our error message. Finally, we return TRUE. Note that
we could return FALSE instead of setting the property to
our error message—in that case we could only get the
properties we’ve set (trying to get undefined properties
we’ve never set would cause a notice).
Let’s test it out. After having overloaded the class, we
set an undefined property (
$$ffoooo
) to 3.14. Next, we get
$$ffoooo
and print it. Finally, we try to get and print anoth-

er undefined property (
$$bbaarr
) we haven’t ever set. The
output is shown below:
3.14
bar isn’t defined
The first value echoed is the one we’ve just set, while
the other is the error message we decided to display.
Overloading methods:
____ccaallll(())
____ccaallll(())
is by far the most interesting feature of over-
loading in PHP, allowing you to call undefined methods.
November 2003

PHP Architect

www.phparch.com
10
FFEEAATTUURREE
Object Overloading in PHP
1 <?php
2
3 class TryGet
4 {
5 var $greet = “Hello World! <br/>”;
6
7 function __get($PropName, &$PropValue)
8 {
9 $PropValue = “$PropName isn’t defined <br/>”;

// Sets the value
10 return TRUE;
// Returns TRUE = doesn’t display errors
11 }
12 }
13
14 overload(‘TryGet’); // Overloads the class
15 $overloaded = new TryGet();
16 echo $overloaded -> greet; // Prints the defined var
17 echo $overloaded -> foo; // Prints an undefined one
18 echo $overloaded -> bar; // Prints another undefined one
19
20 ?>
LISTING 2
It requires three arguments: the name of the method to
call, an array containing the arguments, and the return
value (which is passed by reference). The syntax for
____ccaallll(())
is as follows:
boolean __call([string method_name], [array
arguments], [mixed return_value])
In dealing with
____ggeett(())
, we decided to return an error
message; with
____ccaallll(())
we can’t do anything similar.
Instead, we will look for the undefined method that was
called, and execute it—there may be a function or a
method of another class which has the same name as

the one called. This “magic” method can also return
TRUE or FALSE. In fact, in the next example we’ll return
FALSE if the function method isn’t in the array which
contains the ones allowed to be executed. Just remem-
ber that returning FALSE will cause a warning instead of
a notice. Listing 4 shows an example of how to use
____ccaallll(())
.
Outside of our class we declare function
ggrreeeett(())
; we’ll
need it to demonstrate that
____ccaallll(())
also works with
user-defined functions. Inside the class we’ve left the
constructor empty, and declared
____ccaallll(())
.
Our
____ccaallll(())
function sets up an array (
$$aacccceepptt
) where
we store the name of the functions we will accept as
methods of this class. If the method called is defined in
the
$$aacccceepptt
array, we’ll call the specified function, pass
in the parameter as an array element, and return TRUE.
If the method is not defined in the array, we’ll return

FALSE (a warning). It’s best to allow only a few functions
to be called as a method (just the ones you need).
Now we can test it out. After having overloaded the
class, we try to call three methods: method
ggrreeeett(())
, the
PHP function
ssqqrrtt(())
, and the PHP function
lloogg(())
, echo-
ing each value returned. The output is shown below:
Hi John!
4
Warning: Call to undefined method trycall::log()
Notice that we called a predefined PHP function, but
got a warning. This is because we decided not to
accept
lloogg(())
as a valid method to our class. Also notice
that in
____ccaallll(())
we had to pass the parameter as an
array element (
$$FFuunnccAArrgg[[00]]
). That’s a problem, since it
means we can only call one-argument functions! To fix
this we can use the
ccaallll__uusseerr__ffuunncc__aarrrraayy(())
PHP function.

Its syntax is as follows:
mixed call_user_func_array (callback function[,
array paramarr])
November 2003

PHP Architect

www.phparch.com
11
FFEEAATTUURREE
Object Overloading in PHP
1 <?php
2
3 class TrySet
4 {
5 function __set($PropName, &$PropValue)
6 {
7 $this -> elem[$PropName] = $PropValue; // Stores the prop. and its value in $elem array
8 return TRUE;
9 }
10
11 function __get($PropName, &$PropValue)
12 {
13 if (isset($this -> elem[$PropName])) // If the prop. is in $elem
14 $PropValue = $this -> elem[$PropName]; // Assigns the value in the array
15 else
16 $PropValue = “$PropName isn’t defined <br/>”; // Else sets another value
17
18 return TRUE;
19 }

20 }
21
22 overload(‘TrySet’); // Overloads the class
23 $overloaded = new TrySet();
24 $overloaded -> foo = 3.14; // Sets an undefined property
25 echo $overloaded -> foo . “<br/>”; // And prints it
26 echo $overloaded -> bar; // Prints an undefined and never set property
27
28 ?>
LISTING 3
1 <?php
2
3 function greet($name) // An user-defined function
4 {
5 return “Hi $name! <br/>”;
6 }
7
8 class TryCall
9 {
10 var $accept;
11 function TryCall() { } // Constructor is empty
12
13 function __call($FuncName, $FuncArg, &$RetValue)
14 {
15 $this -> accept = array(“greet”, “sqrt”);
// Array of valid functions
16 if(in_array($FuncName, $this -> accept)):
// If a valid function is called
17 $RetValue = $FuncName($FuncArg[0]);
// Executes the function

18 return TRUE;
// And returns TRUE
19 else:
20 return FALSE;
// Else returns FALSE
21 endif;
22 }
23 }
24
25 overload(‘TryCall’); // Overloads the class
26 $overloaded = new TryCall();
27 echo $overloaded -> greet(“John”);
// Calls greet() as method
28 echo $overloaded -> sqrt(16); // Calls sqrt() as method
29 echo $overloaded -> log(10); // Calls log() as method
30
31 ?>
LISTING 4
ccaallll__uusseerr__ffuunncc__aarrrraayy(())
allows us to call functions and
methods, passing the parameters as an array. Since they
are passed into
____ccaallll(())
as an array, we can now easily
call any function we want. As an example, have a look
at Listing 5.
Here, we set up our class and use
ccaallll__uusseerr__ffuunncc__aarrrraayy(())
to call the function and pass the
parameter array to it. PHP will automatically execute

the function, as long as the script has called the method
with the right number of parameters.
Note that being able to call any function as a method
is not so good. It isn’t necessarily a security issue, since
the call is done by a script of ours, and not an external
user, but it can certainly cause some confusion. The out-
put of Listing 5 is shown below.
12
256
11111010
As we said, we can use a regular function as a method
of our class; but we can also call a method of another
class as one of ours, like so:
$retVal = call_user_func_array( array (
new ClassName(), $MethName),
$MethParam);
That means that by using overloading, we can also
easily extend a class without using the extension mech-
anism.
Now it’s time to write a class which does something
useful with the overloading extension.
Overloading methods: A practice
example
For our example, we will create a class which manages
database operation using the overloading extension.
The database chosen is MySQL, a widely-used open-
source database, and we will be executing queries on
the following sample table:
CREATE TABLE names (
id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,

name VARCHAR( 30 ) NOT NULL)
The purpose of our class is to allow us to use OOP
techniques to perform the most common database
operations, such as:
• Connecting to MySQL and closing the con-
nection
• Selecting, creating and dropping databases
• Sending queries and counting the rows
affected
• Fetching the result data
The code for this example is shown in Listing 6.
Since an open connection to MySQL is always need-
ed to perform any operation, we can put
mysql_connect()
in the constructor of the class, and
store the resource link returned in a class property
(
$$lliinnkk
). In
____ccaallll(())
we decide which functions we’ll
accept, and we store them in two array properties. The
reason for two arrays is that some MySQL functions
require the connection link as the last parameter, while
others don’t. We will automatically add the link to the
parameters of the ones which need it.
We put the functions which need the link in
$$aacccceepptt__ll
,
and the ones that don’t in

$$aacccceepptt
. They are both asso-
ciative arrays—the key is the method name and the
value is the MySQL function name. Note that the prefix
“mysql_”, which each function should have, is omitted
for simplicity and will be added when we execute the
call.
Now comes the most important part of our class. It’s
all contained in an if-elseif-else block.
• If the function called as a method is valid
and requires the connection link, we will add
$$lliinnkk
to the parameters array, call the func-
tion, and return TRUE
• If the function is valid, but doesn’t require a
connection link, we will simply call it and
return TRUE
• If the function is not valid, we will return
FALSE (the script will return a warning)
After having called a MySQL function, the script will
check if it has been successful. If it hasn’t, a MySQL
error message obtained by
mysql_error()
will be dis-
played.
Now our class is complete—we only have to overload
and test it. We create a new object, passing the connec-
tion parameters to the constructor, and then select the
database. Next, we execute a SELECT query on the
November 2003


PHP Architect

www.phparch.com
12
FFEEAATTUURREE
Object Overloading in PHP
1 <?php
2
3 class TryCallParam
4 {
5 function TryCallParam() { } // The constructor is empty
6
7 function __call($FuncName, $FuncArg, &$RetValue)
8 {
9 $RetValue = call_user_func_array($FuncName, $FuncArg);
// Calls the function
10 return TRUE;
// And returns TRUE
11 }
12 }
13
14 overload(‘TryCallParam’); // Overloads the class
15 $overloaded = new TryCallParam();
16 echo $overloaded -> sqrt(144) . “<br/>”;
17 echo $overloaded -> pow(2, 8) . “<br/>”;
18 echo $overloaded -> base_convert(“FA”, 16, 2);
19
20 ?>
LISTING 5

table shown above, fetching and echoing the result.
Finally, we close the connection.
All these operations are performed in OOP. We wrote
less code than with procedural coding, and the code
looks clearer. We performed only a few of the opera-
tions allowed, but you can be sure that the others work
just as well.
This example has shown how we can use the over-
loading extension to organize our code in an object-ori-
ented manner, and simplify it. Of course the class can
be saved in an external file, and included to make the
code even clearer. You can use overloading to group
any set of functions into a class; for instance, you could
create a CURL or Output Buffering class.
Creating Java-like overloading in PHP
At the beginning of this article we explained the “clas-
sic” meaning of overloading. We also explained that in
PHP, we can’t redeclare a method. You might have
guessed that
____ccaallll(())
, though, can help us to do some-
thing similar. It won’t be as elegant as it could be in Java
but... it will work!
Imagine we have a method on which we want to
allow overloading. What we have to do is to prepare
different methods using the original method’s name
concatenated with the number of arguments passed to
November 2003

PHP Architect


www.phparch.com
13
FFEEAATTUURREE
Object Overloading in PHP
1 <?php
2
3 class MySQL
4 {
5 var $link;
6 var $accept_l;
7 var $accept;
8
9
10 function MySQL($server, $user, $pass)
11 { // The constructor opens the connection
12 $this->link = mysql_connect($server, $user, $pass)
13 or die(mysql_error());;
14 }
15
16
17 function __call($FuncName, $FuncArg, &$RetValue)
18 {
19
20 /* Accepted funcs that need a resource link */
21 $this->accept_l = array(“close” => “close”, // mysql_close()
22 “db” => “select_db”, // mysql_select_db()
23 “newdb” => “create_db”, // mysql_create_db()
24 “dropdb” => “drop_db”, // mysql_drop_db()
25 “query” => “query”, // mysql_query()

26 );
27
28 /* Accepted func.s that don’t need a resource link */
29 $this->accept = array(“arows” => “affected_rows”, // mysql_affected_rows()
30 “nrows” => “num_rows”, // mysql_num_rows()
31 “afetch” => “fetch_array”, // mysql_fetch_array()
32 “rfetch” => “fetch_row”, // mysql_fetch_row()
33 “ofetch” => “fetch_object”, // mysql_fetch_object()
34 );
35
36 if(isset($this->accept_l[$FuncName]))
37 { // If the function requires $link
38 $FuncArg[] = $this->link; // Adds $link to the parameters of the array
39 $RetValue = call_user_func_array(“mysql_”.$this->accept_l[$FuncName], $FuncArg)
40 or die(mysql_error());
41 return TRUE;
42
43 }elseif(isset($this->accept[$FuncName])){
44 /* If the function doesn’t require $link calls the function */
45 $RetValue = call_user_func_array(“mysql_”.$this->accept[$FuncName], $FuncArg)
46 or die(mysql_error());
47 return TRUE;
48 }else // If the function isn’t accepted
49 return FALSE; // Returns an error
50
51 } // End __call()
52
53 } // End class
54
55

56 overload(‘MySQL’); // Overloads the class
57
58 $db = new MySQL(‘localhost’, ‘user’, ‘pass’); // Creates the object
59 $db->db(“mydb”); // Selects the db
60 $res = $db->query(“SELECT * FROM names”); // Executes the query
61
62 /* Fetchs and prints the data */
63 while( ($data = $db->afetch($res, MYSQL_ASSOC)) !== FALSE )
64 echo $data[“id”].”: &nbsp;”.$data[“name”].”<br/>”;
65
66 $db->close(); // Closes the connection
67
68 ?>
LISTING 6
it. This would look something like:
“method name” . “argument number”
But –and this is important– we mustn’t declare a
method called “method name”. If we do,
____ccaallll(())
won’t be able to manage the call to our method (since
it wouldn’t be undefined). Listing 7 shows how this all
works.
In method
____ccaallll(())
we first check the number of the
arguments of the undefined method call. Depending
on that, we execute the “right” method. We’ve named
the “right” methods as methname0, methname1,
methname2, etc., depending on how many arguments
they need. When we call

mmeetthhnnaammee(())
, the parser will exe-
cute
____ccaallll(())
, which will determine the right method by
appending to “methname” the number of arguments
passed.
Note that the method to call is indicated as
array(&$this, $FuncName.$NumArgs)
That’s because it isn’t an external function, but a
method of the current object (
$$tthhiiss
). After method
____ccaallll(())
we declare all the methods we may need to
use. Now we can overload the class, and try to call the
methods. The output from Listing 7 will be:
Hello World!
Hello Peter!
Hello John! Greetings from London!
16
81
This feature can be particularly useful if we want to
overload the constructor, which would allow us to build
different objects depending on the number of argu-
ments passed!
Automatically overload a class
As we’ve seen, to overload a class we have to write the
line:
overload(“ClassName”);

This is tedious, especially if the class has been created
to be overloaded. In PHP 5 this is not supposed to be
needed, but now it currently is, we might want to fix it.
If we want to automatically overload a class, we only
have to add this line to the constructor:
overload(get_class($this));
That means that when we build a new object the con-
structor automatically enables overloading support.
This is another detail which may help us to keep our
code clear.
Conclusion
The overloading extension has got great potential. Of
course you can write any application you need without
using it (as you don’t need to use OOP), but it can pro-
vide an intuitive and elegant solution to some prob-
lems; for instance, it can help you to group a bunch of
procedural functions (user-defined or built-in) into a
class library, or to create easily-extensible classes with-
out using the extension mechanism.
Remember that the overloading extension is still
experimental, and the interface and inner workings
may still change drastically, but I expect that it will
become a very powerful coding technique.
I hope this article has helped you to find out how
overloading can make your coding easier. If you have
any questions about it, you can look at the PHP on-line
manual (which unfortunately doesn’t treat this topic
very well), ask on the php|architect forum, or mail me.
November 2003


PHP Architect

www.phparch.com
14
FFEEAATTUURREE
Object Overloading in PHP
1 <?php
2
3 class JavaOverLoad
4 {
5 function JavaOverLoad() { } // The constructor is empty
6
7 function __call($FuncName, $FuncArg, &$RetValue)
8 {
9 $NumArgs = count($FuncArg); // Counts the number of
arguments to find the right meth.
10 $RetValue = call_user_func_array(array(&$this,
$FuncName.$NumArgs), $FuncArg);
11 return TRUE;
12 }
13 /* Some methods... */
14 function greet0()
15 {
16 echo “Hello World! <br/>”;
17 }
18
19 function greet1($name)
20 {
21 echo “Hello $name! <br/>”;
22 }

23
24 function greet2($name, $from)
25 {
26 echo “Hello $name! Greetings from $from! <br/>”;
27 }
28
29 function power1($i)
30 {
31 echo pow(2, $i).” <br/>”;
32 }
33
34 function power2($base, $i)
35 {
36 echo pow($base, $i).” <br/>”;
37 }
38 }
39
40 overload(‘JavaOverLoad’); // Overloads the class
41 $overloaded = new JavaOverLoad();
42 $overloaded -> greet();
43 $overloaded -> greet(“Peter”);
44 $overloaded -> greet(“John”, “London”);
45 $overloaded -> power(4); // It should return 2^4
46 $overloaded -> power(3, 4); // It should return 3^4
47
48 ?>
LISTING 7
About the Author ?>
Click HERE To Discuss This Article
/>Alessandro Sfondrini is a young Italian PHP programmer from Como. He

has already written some on-line PHP tutorials and published scripts on
most important Italian web portals. You can contact him at

Why is it so important?
As you browse through Sourceforge
(
www.sourceforge.net
) in search of the open-source
software that you need, you’ll notice that all of the proj-
ects offer you their source through CVS. If you are not
familiar with Concurrent Versions System (CVS), the first
question is usually: “Why don’t they just pack the files
and distribute it as an archive?”
CVS has multiple uses in software development, so
let’s take a few different angles and try to find out how
you could benefit from it.
Suppose, for a start, that you want to start an open
source project. You want to have a lot of developers
work together from all around the world. So the first
question is: “How can we all work on the same code
base and keep that repository consistent?”
Let’s say that you assign two developers to work on
the same file (e.g.
system/lib/classes/customer.php
). You
give them both accounts on the development server so
that they can copy files to and from their local environ-
ment. It all sounds good at the start, but sooner or later
you’ll get into the following situation. Both developers
get a copy of the file in order to work on different meth-

ods. After a while the first developer puts a changed file
on the server, but he doesn’t remember to notify the
second developer that he should collect a new version
of the file. When the second developer is done coding,
he puts his version of the file back on the server, over-
writing the work of the first developer.
OK, so you can say that communication within the
team should be organized in such a manner as to help
avoid this situation, and you’re right. But in this exam-
ple we assumed only two developers and one file; imag-
ine how would it be when your team expands to
include tens or hundreds of developers and resources.
You shouldn’t have to waste your time and energy
keeping track of concurrent changes in the source—let
software do the dirty work.
The best way is to install a CVS server and make it
public (so everyone can get the latest version of the
source using an anonymous account). Then assign
accounts with commit privileges to your developers so
they can contribute their code to the repository. Your
problem is solved. Every developer has to pull the latest
changes from the repository before he can start work-
ing, and after the work is done he asks the server to syn-
chronize the repository with his changes. If someone
else has committed changes to the same files in the
meantime, the developer is given the opportunity to
resolve any conflicts. This way we are sure that the
source repository is always consistent, and that no code
can mysteriously vanish.
If you are working in the local environment where

your development team is changing the code directly
on the server, you could suppose that this article has no
value for you—but don’t jump to conclusions. CVS is
November 2003

PHP Architect

www.phparch.com
15
FEA
FEA
TURE
TURE
Introduction to Version Control with CVS
PHP: 4.x
OS: Any
Applications: N/A
Code: N/A
Code Directory: N/A
REQUIREMENTS
by Dejan Bosanac
much more then just keeping the code consistent. It
also offers a total history of all code changes. Have you
ever found yourself in the following situation? You learn
that you have to make huge changes to some portion
of the code. You start working, and after a week you
find yourself thinking that you would like to have the
original code back because you realized that there’s a
much easier way to do it. But now you don’t have that
code, and it will take you a lot of time to get it back to

that state (if it’s even possible in the first place). With
CVS, situations like this are not as horrific. You can just
pull the desired code version (or date) from the reposi-
tory, and start all over again.
I’ll mention another benefit of CVS, and I’m sure that
once you start using it, you’ll find that you can’t live
without it. Imagine the following. You find yourself
doing pretty well with your project. You have a large
number of clients that have purchased different ver-
sions of the software. For some of them you had to
make a few customisations, and in some versions differ-
ent bugs have been found. All of a sudden you’re in a
no-win situation again. You could easily get lost with
which code base should be modified or fixed, and you
could end up delivering the wrong update package to
the customer. With CVS you can easily organize your
code in versions and branches, and let the software
take care of that. All you need to do is to checkout the
right branch and version of the code, modify it, check
it in again, and update client’s distribution. Piece of
cake, isn’t it!
Learning by example
Now we’ll go through all of the everyday steps in order
to get the picture on how to use basic CVS commands.
Assume that we started to work on an e-commerce
software project in PHP. On the development server, the
project is in the
/home/web/e-commerce
folder. This is
known as the “working directory” in CVS terminology.

Let’s imagine that we have only three files for now. This
will make our examples clear, but still descriptive
enough.
index.php
login_form.php
login.php
Before we add our project to CVS, CVS should be
properly installed and configured on the desired server.
If you are a Unix/Linux user, then you will probably
have it already on your machine. If this is not the case,
get the source and all the necessary documentation
from the official CVS site (

),
and follow the instructions regarding your particular
system environment. Once you have installed CVS, you
can start using it as a client for other repositories. If you
want to use it as a source repository for yourself, you
should first initialize the repository. You can do this
using the init command
$ cvs -d /usr/local/cvs init
This creates a repository in the
/usr/local/cvs
direc-
tory.
We’re now ready to use CVS in the local environment.
In later sections some other interesting configuration
issues for remote servers will be introduced.
When using CVS as a client, we need to tell the client
program where the code repository is. We can do this

either by using the “-d” switch directly in the command
line (e.g.
cvs -d /usr/local/cvs/
llooggiinn
) or by setting
the
$$CCVVSSRROOOOTT
environment variable, like so:
$ export CVSROOT=/usr/local/cvs)
The first thing we should do is to import our project
into CVS for tracking.
$ cd /home/web/e-commerce
$ cvs import -m “Imported source” e-commerce “OurCompany” start
This command tells CVS that we want to start track-
ing the source in this folder in the repository under the
name “e-commerce” (module name). The “-m” switch
is optional, and it allows us to add an appropriate com-
ment for this action. If it is omitted, CVS will start an
editor to allow us to enter the comment. CVS keeps
track of all the comments that are entered with each
change so that we can have a complete history of all
the important notes for the resource and the project as
a whole. This switch is also used in some other com-
mands, as we will see in a moment.
In the above command, “OurCompany” represents
what’s known as the vendor tag. “start” is a release
tag. These tags may have no role in this context, but
because CVS needs them, they must be present.
Now we can check what have we done. We will
checkout the project from the repository to be sure

that everything is fine, and start working on the source
that is under CVS control. First, we should move the
current project to a temporary folder.
$ mv /home/web/e-commerce /home/web/e-commerce.orig
And do the checkout.
$ cd ..
$ cvs checkout e-commerce
U e-commerce/index.php
U e-commerce/login.php
U e-commerce/login_form.php
The checkout command fetches the latest version of
all the files that are in the repository and puts them in
the “e-commerce” folder. To be sure that this code is
the same as the original code, we could do something
like this:
$ diff -r /home/web/e-commerce /home/web/e-commerce.orig
Only in e-commerce: CVS
You’ll see that the files are exactly the same. Maybe
now is a good time to remove the original source fold-
er, just to be sure that we don’t accidentally edit it
November 2003

PHP Architect

www.phparch.com
16
FFEEAATTUURREE
Introduction to Version Control with CVS
instead of the files that are under CVS. Before you do
this, you may want to consider backing it up some-

where, just in case.
$ rm -r /home/web/e-commerce.orig
If you list the working directory now, you would see
that beside the regular project files we have a “CVS”
directory. It is the system directory used by CVS, and
under normal conditions you should ignore it. It is used
to keep information such as which repository is in use,
what files and versions have been checked out, as well
as all the other useful data about the current working
directory’s state. We will talk about this folder in the
next section, but unless you know what you are doing,
keep away from it or you could damage the tracking
process. CVS directories exist in every subdirectory of
your project that has been checked out.
We said that each time you start working on the code,
you should ask CVS if any changes have occurred in the
files that matter to your work. You can do this by using
the update command.
$ cvs -qn update
You won’t get anything in this example because
we’ve just checked the project out, and all the files are
up-to-date. We will see how this command works later
in the article. The “-q” switch tells CVS to be “quiet”
and print only important information. This is an option-
al switch, but it is very useful if a large number of files
have been changed. The “-n” switch tells CVS not to
do any real updates, but just to show us what needs to
be done. If we omit it, all the files that are shown as not
up-to-date would be updated according to the changes
that are in the repository. If you agree that all the files

should be updated, just repeat that last command with-
out the “-n” switch.
$ cvs -q update
You can update just the files that you are interested
in, rather than getting all the changes. This can be done
by specifying the files of interest at the end of the com-
mand line.
$ cvs -q update index.php login.php
Now we are ready to start working on our source.
Lets say that our
index.php
was like this:
<?
// TODO
?>
We will modify it so that we can show how CVS reacts
to these changes, and describe further steps. Let’s add
some code to the file.
<?
echo “E-commerce 1.0 - under construction”;
?>
It’s not a big progress in the project, but it should be
enough for now. If we try to see the difference between
working copy and the repository, we would get some-
thing like this:
$ cvs -qn update
M index.php
A status of “M” means “locally modified”. It means
that the local copy of the file has been changed and
that those changes have not yet been committed to the

repository. This would seem to be the exact case with
our
index.php
. Some other possible statuses are:
U - “update needed” - means that the local file
version is not accurate and that a newer ver-
sion of the file has been committed to the
repository.
P - “patch needed” - means that the local file
version is not accurate and that file has to be
patched with one in the repository. This is
usually the case when the changes in the file
are not big and CVS could just patch the file
with the current version. It has practically the
same meaning as a status of “U”.
C - “conflict” - means that file could not be
patched (or updated) automatically. We will
see a little bit later how to deal with the con-
flicts.
You can see the differences between the working and
repository versions with the diff command.
$ cvs diff index.php
Index: index.php
==================================================
RCS file: /home/office/cvsroot/test/index.php,v
retrieving revision 1.1.1.1
diff -r1.1.1.1 index.php
2c2
< // TODO
—-

> echo “E-commerce 1.0 - under construction”;
This line will give us the exact changes between the
working and repository versions. If you look at it care-
fully, you can see that in the current version the text “
//
TODO
” has been taken out, while the text “
eecchhoo ““EE--ccoomm--
mmeerrccee 11..00 -- uunnddeerr ccoonnssttrruuccttiioonn””;;
” was introduced in line
two.
The next thing we want to do is to commit our work
to the repository so other developers can use it. We can
accomplish this by doing the following:
$ cvs commit -m “Welcome note added”
Checking in index.php;
/usr/local/cvs/e-commerce/index.php,v <— index.php
new revision: 1.2; previous revision: 1.1
done
Of course, we can also commit on a file basis, just as
with the update command. This is useful in situations
when you have finished one piece of functionality and
started another. You need to submit only the changes
November 2003

PHP Architect

www.phparch.com
17
FFEEAATTUURREE

Introduction to Version Control with CVS
made to some files, because other files are still unfin-
ished. When you want to do this, just append the rele-
vant file names to the command.
$ cvs commit -m “Welcome note added” index.php
We talked about the “-m” switch with the import
command, and it serves the same purpose here: speci-
fying the comment for the action.
If you check for changes now, you’ll see that every-
thing is up-to-date and it’s time to move on with our
project. Imagine that we add some new scripts to our
project; of course we need to add them to CVS reposi-
tory, as well. First we have to create a new file, for
example
logout.php
. You can do it in your favourite edi-
tor or integrated development environment. If you now
check CVS for changes, you will see something like this.
$ cvs -qn update
? logout.php
Our new script is there but with the unusual status
“?”. That means that CVS has no information on this
file, and that the add command should be used.
$ cvs add logout.php
cvs add: scheduling file `logout.php’ for addition
cvs add: use ‘cvs commit’ to add this file permanently
If you now check for changes, you’ll see the “A” sta-
tus, which means that file has been scheduled for
adding, but should be committed in order to finish the
process.

$ cvs -qn update
A logout.php
$ cvs commit –m “Added to the project” logout.php
Checking in logout.php;
/home/office/cvsroot/test/logout.php,v <— logout.php
initial revision: 1.1
done
Now the process is completed.
Of course, one of the common CVS operations is the
removal of files from the repository. Like all of the other
operations, this is quite easy to do. First you have to
remove the file from the working directory.
$ rm logout.php
Then use the CVS remove command to remove it
from the repository
$ cvs remove logout.php
cvs remove: scheduling `logout.php’ for removal
cvs remove: use ‘cvs commit’ to remove this file permanently
$cvs -qn update
R logout.php
Now, you can see that file has been marked with an
“R”, which means that the file is marked for deletion,
but we need to call the commit command to complete
the operation.
$ cvs commit –m “Removed from the project” logout.php
Removing logout.php;
/usr/local/cvs/e-commerce/logout.php,v <— logout.php
new revision: delete; previous revision: 1.1
done
If you are not sure about the statuses that the update

command gives you, you can always find more details
on the file by using the status command.
$ cvs status index.php
===========================================================
File: index.php Status: Up-to-date
Working revision: 1.2 Tue Sep 2 20:34:20 2003
Repository revision: 1.2 /usr/local/cvs/e-
commerce/index.php,v
Sticky Tag: (none)
Sticky Date: (none)
Sticky Options: (none)
We were talking about conflicts before, so now we
will intentionally create one and see how to deal with it.
For that purpose we will need another working directo-
ry.
$ cd /home/web
$ mkdir e-commerce_conflict
$ cvs checkout -d e-commerce_conflict e-commerce
Now we shall modify the
index.php
in our original
e-commerce
directory to be like this:
<?
echo “Debug:”.“E-commerce 1.0 - under construction”;
?>
and commit it. If we now change the
index.php
code in
the

e-commerce_conflict
directory like this:
<?
echo “E-commerce 1.0 - under construction”.“-debug”;
?>
and run the update command, you’ll see the following
message:
$ cvs -q update
RCS file: /usr/local/cvs/e-commerce/index.php,v
retrieving revision 1.1
retrieving revision 1.2
Merging differences between 1.1 and 1.2 into index.php
rcsmerge: warning: conflicts during merge
cvs update: conflicts found in index.php
C index.php
The
index.php
now looks like this
<?
<<<<<<< index.php
echo “E-commerce 1.0 - under construction”.“-debug”;
=======
echo “Debug:“.“E-commerce 1.0 - under construction”;
>>>>>>> 1.3
?>
The conflict has been clearly marked, and you can see
that two different lines have been found at the same
place in the different revisions. You can resolve this con-
flict in one of two ways. You could choose to delete the
local copy and replace it with the version in the reposi-

tory, or you could manually fix the conflicting part of
the code as you see fit, and commit the changes.
<?
echo “Debug:”.“E-commerce 1.0 - under construction”.“ - debug”;
?>
Which approach you choose depends on how many
changes have been made to the file. If your changes are
small, for instance, then it might be easier to just
November 2003

PHP Architect

www.phparch.com
18
FFEEAATTUURREE
Introduction to Version Control with CVS
remove the local copy and start all over.
The commands introduced above cover the most
common tasks that you as a developer will perform with
CVS, and often it is all you need to know.
How does it work?
Let’s turn our focus now to a few advanced CVS topics,
and see how it works “under the hood”. This can be
very useful in cases where you experience difficulty
working with CVS.
We already mentioned the CVS directories that are
placed in the working subdirectories. These directories
keep track of the state of the working directory with
regards to a certain repository. The CVS directories can
contain several files, but here we’ll examine only the

ones that are most important for you as a developer.
The
Root
file contains information about the current
CVS “root”, which is the directory where the CVS repos-
itory lives. This will likely be the directory that we chose
in CVS initialization -
/usr/local/cvs
.
The
Repository
file contains the directory for our proj-
ect in the CVS repository. Remember, one CVS reposito-
ry can be used for several projects. This could be an
absolute or relative path, so our Repository file could
contain
e-commerce
or
/usr/local/cvs/e-commerce
.
The
Entries
file lists the files and directories in the cur-
rent working directory that are under CVS control. It is
a plain text file that contains a file or subdirectory on
each line. You can tell what kind of entry each line is by
examining the first character of that line. If the first
character is “/”, then it is a file entry in the following
format:
/name/revision/timestamp[+conflict]/options/tagdate

• name
is the name of the file within the direc-
tory.
• revision
is the version of the file in the work-
ing directory. It could also be a zero (0) for
newly-added files or a dash followed by a
revision number (-1.1) for removed files.
• timestamp
is a universal time (UT) timestamp
that shows when the file was created by
CVS. If it differs from the file’s modification
time, the file has been changed. If you want
to force the file to always be considered as
modified, you could put a different string
here (e.g. “Always modified”), since CVS
always does just a simple string comparison.
• conflict
indicates that there was a conflict
during the file update, and if the file modifi-
cation time is the same as the timestamp it
means that the developer hasn’t resolved the
conflict yet.
• options
and tagdate are connected with revi-
sion numbers and sticky tags, which are not
going to be covered by this article
An example file entry could look like this:
/index.php/1.6/Thu Sep 25 23:01:21 2003+conflict//
The format for directory entries in the Entries file is:

D/name/filler1/filler2/filler3/filler4
• name
is the name of the subdirectory
• filler
fields are left for future enhancement.
An example entry for the system subfolder would be:
D/system////
Now that you know how the working directory CVS
directories are organized, we will briefly go through the
repository organization, which will give us an idea of
how the other side works. The repository is just a direc-
tory on your server (or a remote server, as we will see
later). Project files are stored in the repository with
names that are the same as the working names with
“,v” appended to the end. These files are known as his-
tory files or RCS files. They contain enough informa-
tion to recreate any version of the file. These files also
contain all of the comments that were entered in the
import and commit process (remember the “-
m”switch). This way a complete log history of each file
can be generated (including the usernames of the com-
mitters).
Sometimes CVS stores RCS files in the
Attic
subdirectory. If we suppose that our CVSROOT
is
/usr/local/cvs
, then it is normal that the history
file for the
index.php

in the
e-commerce
project would
be
/usr/local/cvs/e-commerce/index.php,v
. If the file
was removed, it is stored in the
Attic
subfolder (in our example,
/usr/local/cvs/e-com-
merce/Attic/index.php,v
). As an aside, if you fol-
lowed all of the operations in the first part of this
article, and you are able to cd into the CVS
repository, you should find
logout.php
in the
Attic
directory.
In the repository you will also find the CVSROOT
directory. This directory contains administrative files.
For a complete list of all possible administrative files and
their organization, you should check the CVS documen-
tation. Here we will mention only the modules file, as
that is the most important one for us.
The modules file can be used to create aliases and to
group project resources into logical modules. It is a
plain text file with one line for every module or alias.
Lines can be continued over more than one line, by
appending the backslash (“\”) character to the end of

each line.
Aliases have the following syntax:
November 2003

PHP Architect

www.phparch.com
19
FFEEAATTUURREE
Introduction to Version Control with CVS
alias_name –a what_to_alias
For example, let’s go back to our
e-commerce
directory
from earlier. If we don’t like typing “e-commerce” all
the time, we can define an alias.
ecom -a e-commerce
This would make the result of the following two com-
mands the same.
$ cvs checkout e-commerce
$ cvs checkout ecom
Modules are defined as:
module_name [options] directory [files...]
for example
ecom e-commerce
This way when you do a checkout you will get an
ecom
directory, instead of
e-commerce
, although the files will be

the same.
$ cvs checkout ecom
By specifying a filename behind the directory name in
the module file, you can include only those files in the
module, rather than the whole directory. This might be
useful, for example, if your project is split into logical
sub-systems.
ecom e-commerce login.php
If you now do the checkout, you will only get the
file(s) you specified.
A module definition can include other modules. If you
want to do that you should add an ampersand (“&”)
sign before the module name.
ecom &e-commerce &other_module
Administrative files are stored in the CVSROOT direc-
tory in RCS format, just like regular project files, but a
working copy of each file should also be present. So for
the
modules
file, you should find both
modules,v
and
mod-
ules
there. You can freely edit any of the administrative
files the same way you edit the project file. All you have
to do is to check it out, change it, and commit it back
to the repository.
$ cvs checkout CVSROOT
$ cd CVSROOT

[edit modules file]
$ cvs commit -m “CMS module added” modules
Of course, you should be careful with this process as
it could affect general CVS behaviour. Only modify
administrative files if you know exactly what you are
doing.
Adapt it to your organization’s needs
Now that we know all the basic things about CVS, we
can go a little further and see how you can adapt it to
your specific organization’s needs.
The first thing you should think about is the location
of the CVS server. All of our previous examples assumed
that the CVS repository is on the same server as the
working directory. This is acceptable in some cases, but
not always. If we go back to the example of the open-
source project with developers spread all over the
world, this configuration would not be very useful.
What we need is a CVS server that is publicly available
via the Internet for developers to use. Fortunately, using
remote repositories is as easy as using local ones. All you
have to do is to use the following format for your CVS-
ROOT (specified either with “-d” switch or in an envi-
ronment variable as we saw above):
:method:user@hostname:path_to_repository
method
indicates what authentication method is in use.
You can connect to CVS using rsh, kerberos or pass-
word (pserver) authentication. In this article we will
focus on the password authentication; for more details
on other connection methods you should consult the

CVS documentation. Connecting with password
authentication is useful in the situation when rsh or
Kerberos are not available for some reason. First of all
you should set up your inetd to correctly receive con-
nections for CVS on the appropriate port (2401 by
default) and to execute the “cvs” command. Usually,
adding the following line in
/etc/inetd.conf
should be
sufficient.
2401 stream tcp nowait root /usr/local/bin/cvs
cvs —allow-root=/usr/local/cvs pserver
Separate CVS and system account passwords can be
introduced, which is very useful because pserver
authentication sends plain-text passwords through the
network, meaning that system accounts could be com-
promised.
Setting up a separate CVS account password is done
using the
$CVSROOT/CVSROOT/passwd
file. This is a plain text
file that can be created and modified with any text edi-
tor. It’s in the same format as the
/etc/passwd
file except
it has only three fields: cvs_username, password,
optional_system_username. The optional username
allows you to map your desired cvs username with the
appropriate system account. This means that if you
authenticate as

cvs_username
, you would end up using
the CVS server under the
optional_system_username
sys-
tem identity.
Passwords are encrypted with the standard Unix
ccrryypptt(())
function so it is possible to copy and paste pass-
words from the
/etc/passwd
file. In this case you should
consider protecting the
$CVSROOT/CVSROOT
directory with
the same privileges as the
/etc
directory to prevent
malicious users form compromising your CVS server.
If CVS can’t find a username or the passwd file it will
try system user look-up (system password file, LDAP,
November 2003

PHP Architect

www.phparch.com
20
FFEEAATTUURREE
Introduction to Version Control with CVS
etc) in order to try to authenticate the user. This feature

can be disabled by specifying a “
no
” value for the
SSyysstteemmAAuutthh
variable in the
$CVSROOT/CVSROOT/config
file.
On the client side, the user just has to use the cvs
command specifying the remote repository with the
pserver authentication method (either using “-d” or
storing it in the
$$CCVVSSRROOOOTT
variable). When you are access-
ing the remote repository for the first time, you have to
login. That is done using the login command, which
will prompt you to enter your password.
$ cvs -d :pserver::/usr/local/cvs login
Logging in to :pserver::2401/usr/local/cvs
CVS password:
After logging in, your password will be stored in the
$HOME/.cvspass
file. The password is not stored in plain
form, but it is trivially encoded and could be easily com-
promised. This is, along with sending passwords in the
plain-text form, the biggest security flaw of the pserver
method of CVS authentication. The location of this
client password file can be changed by setting the
CCVVSS__PPAASSSSFFIILLEE
environment variable.
Now we’ve solved the problem of remote access to

the project repository for developers, but that is not
enough. What we want to do is ensure that everyone
can obtain the source of the project, but that only the
core developers can commit changes. This can be done
by using an anonymous account with the pserver
authentication method. An anonymous account can
be created by inclusion (a username is explicitly marked
as the read-only account) or by exclusion (username is
not on the list of users with write privileges). For this
purpose you use the
readers
and
writers
files in the
$CVS-
ROOT/CVSROOT
directory. You can create and modify these
files (as well as the
passwd
file) in the same way as we did
the
modules
file earlier. In the
readers
file put all user-
names that you want explicitly to have a read-only
account, for example
anonymous
guest
In the

writers
file you should explicitly declare all the
usernames that have write privileges, for example
dejanb
arno
All of these usernames must exist in the CVS
passwd
file
or on the system. The authentication method then goes
like this (once the user is authenticated):
• If the
readers
file exists with that username list-
ed, then the user gets read-only access.
• If the
writers
file exists and there is no given
username there, then the user would get read-
only access again.
• Otherwise, the user gets write access to the
repository.
There could be a conflict situation, too. If a username
exists in both
readers
and
writers
files, that user gets
read-only access.
Now we have all that we need to start working on our
project.

Branches
CVS is not restricted to linear development. You can
create branches of your source, which could be valu-
able for fixing bugs in previously-released versions of
your project. Let’s say that we have released version 1.0
of our e-commerce suite, and continued on to work on
the 1.1 release. After a while, a client calls and reports a
bug in the code, but our repository has changed since
that release and we don’t have an accurate version of
the source to work on.
Every branch has its own number. Branch numbers
consist of an odd number of period-separated integers.
The revision number of the file being branched
becomes the branch number followed by a period and
an integer. In Figure 1 we can see examples of the file
revision and branch numbers.
It can be very useful if we make a branch of the code
after every project release. Use the tag command with
the “-b” switch to name the branch.
$ cvs tag -b e-commerce-1-0
cvs tag: Tagging .
T index.php
T login.php
T login_form.php
Now, when you need a working copy of some earlier
product release, you can access it by using the “-r”
switch with the name of the branch on checkout and
update commands. First, you need to checkout the
branch and create a working directory for it.
$ cd /home/web

$ cvs checkout -r e-commerce-1-0 e-commerce
After you made modifications you wanted, you can
commit it as before and changes will be applied in the
desired branch and not in the main development
branch. If you want to get any changes that other
developers made in the desired branch, you could use
the “-r” switch with the update command
$ cvs update -r e-commerce-1-0
There are many other possibilities with branching,
November 2003

PHP Architect

www.phparch.com
21
FFEEAATTUURREE
Introduction to Version Control with CVS
such as merging branches back into the main develop-
ment branch, but they are outside the scope of this arti-
cle.
CVS Tools
Until now, we only talked about the CVS server and
command-line client commands. If you like to work in a
window-based, graphical environment and find your-
self uncomfortable with typing commands, there are lot
of solutions that you can use.
Many modern integrated development environments
(IDE), for example, support CVS. You could use Eclipse
(


) with the PHP plug-in
(

) and benefit from the
power of their integrated GUI for CVS access.
It seems that the majority of script developers tend to
just use a good text editor for their development (no
matter whether they work in Windows or Unix environ-
ments), so we will focus on a few standalone applica-
tions that could make your client CVS tasks easier.
Tortoise CVS (
/>) is
Windows-based tool that allows you to inte-
grate basic CVS commands into Windows
Explorer. After installation you can find extra
options on your right-click menu that allow you
to update, commit, or do anything you need
with your code. See Figure 2.
CVSGui (

) is a set of GUI’s
available for the Windows, Macintosh, or
Unix/Linux environments. It’s a powerful appli-
cation that uses the native look-and-feel of
your operating system. It contains a file brows-
er, a module browser, command line support,
and many other advanced features that can
help experienced users to automate their tasks.
See Figure 3.
Chora (

/>) is a PHP
application that allows you powerful file data
(authors, logs, differences) browsing and graph-
ical branch representation.
CVSweb
(
/>) - is a
single Perl script written originally for the
FreeBSD project. Over time it has earned great
popularity among software developers. It
enables you to browse a repository’s revision
history with a web
browser.
November 2003

PHP Architect

www.phparch.com
22
FFEEAATTUURREE
Introduction to Version Control with CVS
Figure 3
Further steps
If you’re planning a potentially large project, you’ll def-
initely need a version control system, and you’re better
off to do it from the start. CVS is a proven tool for the
job, and has a huge resource base. Many developers
are familiar with it, reducing the need for extra training,
and there are a plethora of tools out there for working
with CVS, including source tree analysis.

This article has only covered the tip of the iceberg
with CVS and associated tools. There’s much more to
learn, and you’ll find a ton of information on the web,
so check it out!
November 2003

PHP Architect

www.phparch.com
23
FFEEAATTUURREE
Introduction to Version Control with CVS
Figure 2
About the Author ?>
Click HERE To Discuss This Article
/>Dejan Bosanac works as a fulltime software developer for DNS Europe Ltd
() on the Billing software system for ISP's. In
his spare time he also serves as a Lead Engineer at Noumenaut Software
() on the online journaling project. He holds
a Bachelor degree in Computer Science and currently is on the master
studies in the same field.
FavorHosting.com offers reliable and cost effective web hosting...
SETUP FEES WAIVED AND FIRST 30 DAYS FREE!
So if you're worried about an unreliable hosting provider who won't be
around in another month, or available to answer your PHP specific
support questions. Contact us and we'll switch your information and
servers to one of our reliable hosting facilities and you'll enjoy no
installation fees plus your first month of service is free!*
Please visit />call 1-866-4FAVOR1 now for information.
- Strong support team

- Focused on developer needs
- Full Managed Backup Services Included
Our support team consists of knowledgable and experienced
professionals who understand the requirements of installing and
supporting PHP based applications.
Can’t stop thinking about PHP?
WWrriittee ffoorr uuss!!
Visit us at
/>

×