All the richness that you can find in a desktop application is absent: the form only refreshes upon submit, a lot more code is needed to make a dynamic UI, HTML cannot support ‘complex’
Trang 2Certification Central
Trang 4by Andi Gutmans and Marco Tabini
Managing Distractions and Engineering Abstractions
Practical Caching for the PHP Developer
TM
Trang 5*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.
Choose a Subscription type:
CCaannaaddaa//UUSSAA $$ 9977 9999 CCAADD (($$6699 9999 UUSS**)) IInntteerrnnaattiioonnaall AAiirr $$113399 9999 CCAADD (($$9999 9999 UUSS**))CCoommbboo eeddiittiioonn aadddd oonn $$ 1144 0000 CCAADD (($$1100 0000 UUSS))((pprriinntt ++ PPDDFF eeddiittiioonn))
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.
VISA Mastercard American Express
Credit Card Number:
Expiration Date: _
more information or to subscribe online.
Signature: Date:
php|architect
The Magazine For PHP Professionals
Subscribe to the print edition and get a copy ofLumen's LightBulb — a
$499 value absolutely FREE †!
Login to your account
for more details
EXCLUSIVE!
† Lightbulb Lumination offer is valid until 12/31/2004 on the purchase of a 12-month print subscription.
Trang 6Graphics & Layout
php|architect (ISSN 1709-7169) 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 associated material.
Contact Information:
General mailbox: info@phparch.com
Editorial: editors@phparch.com
Subscriptions: subs@phparch.com
Sales & advertising: sales@phparch.com
Technical support: support@phparch.com
Copyright © 2003-2004 Marco Tabini & Associates, Inc — All Rights Reserved
Ihave a confession to make I’m an XML-phobe I know, in today’s
soci-ety of political correctness and respect for other cultures, that’s nothing
short of inexcusable, but what can I say? I’m getting old and, therefore,
cranky.
When I first heard of XML a while back, I couldn’t help but thinking of
it as the answer to a question nobody asked This feeling was, in fact,
aug-mented by the continuous misuse of this outrageously verbose in all sorts
of places where it really didn’t belong Have a configuration file? Let’s
make it XML Need to store data? Why use a database—we have XML!
At the time, I was part of a team whose job was interfacing a
Microsoft-based web system to a legacy mainframe system, which, at the time, was
no walk in the park, as everything had to take place through a
carefully-choreographed exchange of text files I remember that, at some point, the
irony of it all struck me: here was a perfect scenario in which being able
to use XML would have been, at last, beneficial (although manipulating
text files with ASP was about as pleasant as stapling your lips together)
and, of course, there was no way I could have used it, because it would
have required too much work on the mainframe side On the other hand,
I had to use XML for pretty much half of the configuration files on the
Windows machine Lovely.
As time has gone by, the XML craze has somewhat faded to a more
rea-sonable level: we now use it for its intended purpose—the structure
com-munication of data between two or more heterogeneous systems—more
often than not It has become the basis of XHTML, whose importance is,
in my opinion, not in the beauty of a “well-designed” web page, but in
the fact that any robot should be able to parse XHTML, thus paving the
way for better search engines, more focused online advertising, and so on.
Still, despite (or, more probably, because) XML was designed to be a
human-readable format, manipulating an XML document “by hand” is
not fun—regardless of how good your particular platform is at handling
strings and arrays What it takes is a strong set of tools designed
specifical-ly to parse, modify and produce XML documents and are capable of
inter-facing with the underlying platform in a way that hides the minutiae of
the language from the developers
PHP 4 had what could be considered a germinal XML infrastructure, but
with PHP 5 we now have a robust toolset (despite a few kinks here and
there) that can be used to perform all sorts of XML manipulations—and
which will be indispensable to the introduction of PHP in an enterprise
environment that requires interoperation between a variety of different
systems
I had a taste of just how important this is to our readers during
php|works, when I sneaked into Ilia Alshanetsky’s session on PHP 5 and
XML… and had to leave because I couldn’t get a seat Once the
confer-ence was over, therefore, I had to ask Ilia if he wanted to write a
compa-rable article for the magazine; the result is this month’s main piece.
As usual, Ilia came through in style with an article that explores every
single facet of the functionality available in PHP 5 (with a quick look at
what was available in PHP 4), with plenty of practical examples and
Trang 7Zend announces the PHP 5 Coding Contest Winners
Zend has released the names of the winners of the PHP 5 Coding Contest!!
“ It really wasn’t that easy to choose between the top applications; there are quite
a few that ended up in the top 20 or so that could just have easily been in the
top 6 Without your input, we’d still be arguing over them!
A special mention goes to MyObjects * , a project that provides its own persistent
object library and tools for generating classes directly from a MySQL database A
minor coding style issue was all that prevented the project from being one of the
top prizewinners The voters liked it too, and it ended up coming in 7th place.
Keep an eye out for the author, Erdinc Yilmazel of Turkey - we’d put money on
his winning next time, if there’s a next time!
Another special mention goes to Hive ** , which came in 41st because nobody in
the public domain voted for it We disagreed it ranked 3rd in the judges list
-so we’ve scrambled around to find a judges prize for the author, Robert
Janeczek Ironically, Robert describes Hive as ‘a low-level version of the PRADO
project’
Our judges and the public agreed over PRADO *** , which won outright All we
need to do now is get a laptop to Qiang Xue, the author of the winning
applica-tion, and then we can sit around in the office drinking too much caffeine and
playing hangman with a clear conscience “
For more information, and to try the winning software for yourself, visit
MySQL 4.1 can be downloaded now
guest-PHPX is a constantly evolving and changing Content Management System (CMS) PHPX is highly cus- tomizable and high powered all in one system PHPX provides content management combined with the power of a portal by including in the core package modules such as FAQ, polls, and forums PHPX uses dynamic-template-design, what this means is that you have the power to control what your site will look like.
Themes are included, but not required You can create the page however you want, and PHPX will just insert code where you want it.
No more 3 columns if you don’t want it! Written in the powerful server language, PHP, and utilizing the amazingly fast and secure database MySQL, PHPX is a great solution for all size website communities, at the best price possible free! “
Zend Encoder for MAC OSX Now Available
Zend has announced the release of Zend Encoder for Mac OS X.
“ The Zend Encoder is the recognized industry standard in PHP intellectual property
protection The Zend Encoder allows an unlimited number of PHP applications to
be distributed, while ensuring your investment and source code are protected
from copyright infringement.
Independent Software Vendors (ISV’s) and Professional Service Providers (PSP’s)
rely on the Zend Encoder to deliver their exclusive and commercial PHP
applica-tions to customers without revealing their valuable intellectual property By
pro-tecting their PHP applications, these and other enterprises expand distribution
and increase revenue.
The Zend Encoder compiles and converts plain-text PHP scripts into a
platform-independent binary format known as a ‘Zend Intermediate Code’ file These
encoded binary files are the ones that are distributed instead of the
human-read-able PHP files The performance of the encoded PHP application is completely
unaffected!
The Zend Optimizer, a free download, is the run-time environment that enables
end-users to transparently execute these files as if they were regular PHP scripts.
The Zend Optimizer not only provides an additional level of increased security
against reverse engineering, it also improves performance speed “
For more information visit: www.zend.com
Trang 8Apache HTTP Server 1.3.33 Released
From Apache.org:
“ The Apache Software Foundation and The Apache HTTP Server Project are pleased to announce the release of version 1.3.33 of
the Apache HTTP Server (“Apache”) This Announcement notes the significant changes in 1.3.33 as compared to 1.3.31 (1.3.32
was not formally released) The Announcement is also available in German and Japanese
This version of Apache is principally a bug and security fix release A partial summary of the bug fixes is given at the end of this
document A full listing of changes can be found in the CHANGES file Of particular note is that 1.3.33 addresses and fixes 2
potential security issues: CAN-2004-0940 * Fix potential buffer overflow with escaped characters in SSI tag string And
CAN-2004-0492 ** Reject responses from a remote server if sent an invalid (negative) Content-Length
We consider Apache 1.3.33 to be the best version of Apache 1.3 available and we strongly recommend that users of older
ver-sions, especially of the 1.1.x and 1.2.x family, upgrade as soon as possible No further releases will be made in the 1.2.x family.
“
Apache 1.3.33 is available for download from http://httpd.apache.org/download.cgi
* http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0940
**http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0492
PostNuke Security Alert
Postnuke.com has posted a new security alert regarding a Hack into the the ZIP archive of PostNuke 750
“ We discovered last night that http://downloads.postnuke.com was the target of a malicious attack and files in the ZIP archive
of PostNuke 750 were changed Immediately upon discovering this all links to the downloads section were removed and on
Tuesday the 26th at 8:30 GMT the original download package was restored.
Our investigations so far have revealed the attack was initiated on Sunday, 24.Oct, at 23:50 (11:50 PM) GMT The attacker used
an exploit in the download management software pafiledb to change the download address of PostNuke-0.750.zip to point to a
compromised archive We must stress this is a security compromise of paFileDB and has nothing to do with the PostNuke
appli-cation.
Note, if you downloaded the tar.gz archive you are not affected so you do nothing, only those who downloaded the zip version
were affected and must take immediate action as detailed below.
The changes made by the hackers were in two places First, during the installation routine all data submitted (this includes the
server, the database credentials, the admin name and password) is sent to a different server Second, in one file there was code
allowing a malicious user to execute any shell command on the web server.
As noted before, immediate action is required from everyone who downloaded the zip package between Sunday (24.Oct) at
23:50 GMT until Tuesday (26.Oct) at 8:30 GMT “
For more information visit: news.postnuke.com
Take Advantage of Marco’s Wonky Math and Save Up to $80
Our fall/winter 2004 subscription campaign is in full effect—and this year we have some great offers for all our scribers, regardless of whether you’re becoming a member of our family for the first time or if you’re been looking forward for your copy of php|a since the very beginning.
sub-Signing up for a php|a subscription (or adding another 12 months to your existing one) right now means some great offers, which include:
• A $80 discount on the Zend Certification Guide
• A free 64MB USB Memory Key, complete with the php|architect logo
For more information, visit our website at http://www.phparch.com/wonky
Errata
In last month’s Tips & Tricks column, John mentioned that a reader had pointed out a small flaw in his random-line access
algo-rithm In true php|architect fashion, we misspelled his name—quoting him as Chris Cowell, while his real name is Chris Dowell Sorry, Chris!
Trang 9Looking for a new PHP Extension? Check out some of the lastest offerings from PECL.
WinBinder 0.27.093
WinBinder is an extension that allows PHP programmers to build native Windows applications It wraps a limited but important subset
of the Windows API in a lightweight, easy-to-use library so that program creation is quick and straightforward.
Parsekit 1.0
This package provides a userspace interpretation of the opcodes generated by the Zend engine compiler built into PHP.
This extension is meant for development and debug purposes only and contains some code which is potentially non-threadsafe.
Imlib2 0.1
imlib2 is a very fast image manipulation library, but without the support for as many image formats as other libraries such as
imagemagick.
You will need the imlib2 library from http://sourceforge.net/projects/enlightenment/ in order to compile this extension.
This extension is experimental It's been tested on a number of Linux installs, but nothing else Please report any bugs to the
main-tainer!
Translit 0.1
This extension allows you to transliterate text in non-Latin characters (such as Chinese, Cyrillic, Greek etc) to Latin characters Besides the transliteration, the extension also contains filters to convert to upper- and lower-case words in Latin, Cyrillic and Greek, and per- form special forms of transliteration, such as converting ligatures such as the Norwegian "ÃE" to "ae," as well as normalizing punctua- tion and spacing.
Check out some of the hottest new releases from PEAR.
PHPUnit 2.1.2
PHPUnit is a regression testing framework used by the developer who implements unit tests in PHP.
DB_odbtp 1.0.2
DB_odbtp is a PEAR DB driver that uses the ODBTP extension to connect to a database.
It can be used to remotely access any Win32-ODBC accessible database from any platform.
Mail_mbox 0.3.0
This extension can split messages inside an Mbox, return the number of messages, return, update or remove a specific message, or
add a message to it.
I18Nv2 0.9.1
This package provides basic support to localize your application, like locale based formatting of dates, numbers and currencies.
It also attempts to provide an OS-independent way to sseettllooccaallee(()) and aims to provide language and country names translated into many languages It provides these classes:
• I18Nv2-OS-independent (Linux/Win32) sseettllooccaallee(()), other utilities
• I18Nv2_Locale-locale based formatter
• I18Nv2_Negotiator-HTTP negotiation of preferred language and charset
• I18Nv2_Country-multilingual list of country names
• I18Nv2_Language-multilingual list of language names
• I18Nv2_Charset-list of common and not so common charsets and aliases
• I18Nv2_AreaCode-list of international area codes (phone)
Stream_Var 1.0
Stream_Var can be registered as a stream with ssttrreeaamm rreeggiisstteerr wwrraappppeerr(()) and allows stream-based access to variables in any
scope Arrays are treated as directories, so it's possible to replace temporary directories and files in your application with variables.
Trang 10Distractions Abound
Apparently, a few of our loyal readers have been
won-dering just when Part II of this series would come out,
or whether it had vanished into the //ddeevv//nnuullll
bitbuck-et Please bear with me; since writing that first article I
have gone through three South Florida hurricanes and
the birth of my second child (a boy!) So, suffice it to
say that there have been a few distractions in my life
But, in the best tradition of making lemons into
lemon-ade, let’s think about what distractions can teach us
Foremost, I would have to say that they highlight the
need to think clearly and accomplish as much as
possi-ble in the shortest possipossi-ble time (and if my parents had
known when I was 16 that I would grow up to write a
line like that, they would truly believe in miracles)
With that in mind, let’s think about how databases
help us manage distractions I have a very small
synop-sis of what the relational model of data affords us: the
ability to name things in order to control them That may
seem a tad simplistic, but think about it: relational
data-bases give us the ability to apply a distinct and clear
name with a value attached to everything—and, most
importantly, they don’t require any other mechanism
than a simple declaration of the named element and its
attributes in order to retrieve the associated value In
other words, you don’t need to think about “the
infor-mation in column #2 of row #34,” or “the eeyyee ccoolloorr
field is in column #4 of this table.” Instead, the
mecha-nism for accessing your data simply is the statement of
what you are looking for “Get all eeyyee ccoolloorr values for
employees born before 1968” can be directly
translat-ed into SSEELLEECCTT eeyyee ccoolloorr FFRROOMM eemmppllooyyeeee WWHHEERREE
eemmppllooyy eeee bbiirrtthhddaayy >>== ‘‘11996688 0011 0011’’;; The fact that most base systems also allow you to ask for the data on row
data-#34 and the value in column #2 should be regarded as
a nuisance rather than a feature, if you truly follow theprinciples of relational database design
Distractions also teach us that abstraction helps us
manage the organization of our lives If we had to thinkabout every single step we took, we would be prettyfrustrated by the end of the day, but our bodies allow
us to abstract that into a general concept called ing.” Thus, rather than thinking about moving our feet
“walk-up and down in the exact steps we will have to take inorder to get to the refrigerator, we just decide to walk
to the refrigerator, and let the abstraction take over(believe me, with a wife, a 4-year-old and a newborn, Ihave been doing a lot of walking to the refrigeratorlately) In the same way, both relational database sys-tems and object-oriented programming allow us to cre-ate abstractions that save us time in the future Theyjust do so in different ways
What’s wrong with this picture?
As we discussed in Part I, one of the biggest distractions
in modern programming is the “object-relational
by Rick Morris
PHP: 4.x+
OS: Any Other software: PostgreSQL version 7.4+
Code Directory: relational
REQUIREMENTS
To many object-oriented developers, there is a sense that
the relational model for data management is at odds with
the concepts of object-oriented development Are these
views justified? Are they practical? In part II of this
two-part series, we build a simple example of an
object-orient-ed application that derives business logic from the
data-base without object/relational mapping.
Managing Distractions and
Reverse-Engineering
Abstractions
Trang 11impedance mismatch.” For example, let’s look at a
basic SQL query and online form that a PHP developer’s
apprentice might create Our developer has been wise
in taking advantage of abstraction, so she uses the PEAR
HHTTMMLL QQuuiicckkffoorrmm class to generate the form for a simple
user signup script (see Listing 1) It is, undoubtedly, a
nice choice—and kudos to our aspiring guru for taking
the time to read, instead of just hacking a quick-n-dirty
HTML form with interspersed PHP We will, for the
moment, assume that $$ddbb is an instance of a database
abstraction class with nice methods like ccrreeaattee eennttrryy(())
and llaasstt eerrrroorr(())
This example might look nice, clean and readable—
really a pleasure to look at if you are tired of the
spaghetti code littering many web-based applications
So what’s wrong with it? Well, just think about what
has to be done if you have to modify the database: your
developer will have to modify every script that interacts
with the table and other DB structures that have been
changed Amazingly, this is the expected—and
accept-ed—state of affairs for most application programming
out there, especially in the area of web-based software
The benefits of the relational model are often seen to
be at odds with the capabilities of Object-oriented
Programming While the relational model is based on
set-oriented thinking, which presents a unified logical
method of accessing and modifying all kinds of data,
object-oriented programming provides a metaphorical
approach to data and essentially uses custom functions
to bundle behaviors with it While at first it seems
logi-cal that one would just develop objects in parallel with
the tables in one’s logical database design, we saw that
this leads to a fundamental problem: you inevitably end
up duplicating effort, as you slavishly model one ronment to follow the other
envi-Really, the best parallel to objects and behaviors inthe relational world could be datatypes and operators.Think about it The real objection is that datatypes areseen as “scalar” and “primitives,” but there is actuallynothing in the relational model itself that preventsdatatypes/domains from being complex, composite, oreven customized by the user, along with customizedoperators This begs the question, however, since mostdatabase systems don’t have a truly comprehensiveway to deal with custom datatypes However, we can atleast take a step in that direction with the use ofdomains
A Note on Terminology:
Since this is an attempt at a serious look at what can beaccomplished by programming in accordance with therelational model, we will use relational terminology.Rather than “datatype”, we will refer to “domain” and,rather than “table,” we will use the term “relation”.There is a good reason for this: we should be able totreat custom domains the same way as baseline scalardatatypes like IInntt and, in fact, a domain is simply the
“set of all possible values” for a certain term (thinkabout your high school algebra) Also, a table is a rela-tion, but so is a view (in fact, so is the result set fromany query or stored procedure) The point here is thatthere is a decided advantage to our programming
front-end if we don’t make distinctions between
datatypes and custom domains, or between tables and
views Your application front-end has noreal need to know the underlying design
of your database, but simply what is sented to it by the developer Also, since
pre-we are discussing an object-orientedframework for PHP as it interacts withrelational databases, every classname willhave the prefix RReell This is especially nec-essary since PHP—even version 5—doesnot have namespaces
What would happen, though, if we did
associate every datatype in our DBMS(along with custom domains and com-posite types), to a class in our program-ming framework? Of course, there wouldstill have to be some work done to tie inthe application framework with the data-base, but it would not have to be associ-ated with specific business logic, focusinginstead on more generic, abstract con-cerns—the perfect case of code reuse, ifyou will
Now, what would happen if youdesigned other classes “by composition
7 $form = new HTML_QuickForm ( ‘user_signup’ , ‘get’ );
8 $form -> addElement ( ‘header’ , ‘’ , ‘New User Sign-up’ );
9 $form -> addElement ( ‘text’ , ‘username’ , ‘Username’ );
10 $form -> addElement ( ‘password’ , ‘password’ , ‘Password’ );
11 $form -> addElement ( ‘text’ , ‘firstname’ , ‘First Name’ );
12 $form -> addElement ( ‘text’ , ‘lastname’ , ‘Last Name’ );
13 $form -> addElement ( ‘text’ , ‘email’ , ‘Email Address’ );
14 $form -> addElement ( ‘reset’ , ‘btnClear’ , ‘Clear’ );
15 $form -> addElement ( ‘submit’ , ‘btnSubmit’ , ‘Submit’ );
16
17 $form -> addRule ( ‘username’ , ‘Your username is required’ , ‘required’ );
18 $form -> addRule ( ‘password’ , ‘Your password is required’ , ‘required’ );
19 $form -> addRule ( ‘email’ , ‘Your email address is required’ , ‘required’ );
Trang 12rather than inheritance” to automatically “know” what
to do when presented with a specific table, query, or
other database construct, given that you already have a
class that parallels each datatype? Are these just
rhetor-ical questions? Not really
If you think this through a little, you’ll find that the
concept we presented in the last article hints exactly at
this type of solution In other words, rather than the
peculiarly brittle approach of creating a parallel class for
every table, we instead opt to model orthogonal
con-cerns, leaving us much freer to change one aspect of
the system without changing another Now, if we want
to change the way our application deals with
autonum-bered primary key columns, for example, we just have
to change it in one place, instead of many Adding
val-idation capabilities to our front-end is not such a
frus-trating experience anymore
If you use domains, you have even more control For
example, if you decide that wherever the “zipcode”
domain is used as a column definition, you want the
application to present it in the Courier font, it is a
one-time change (I’m sure you can imagine far more usefulways of applying this approach to your own applicationproblems)
Of course, in order to do this sort of thing, you notonly need a class for every domain, but you also need
a way to “reverse engineer” every relation that you aredealing with, in order to get the metadata for columndefinitions, datatypes used, primary keys, and so on
“What a huge task,” you might be thinking.Fortunately, most of this work has already been donefor you; if you use either MySQL or PostgreSQL, youwill easily realize that phpMyAdmin and phpPgAdminhave code that accomplishes all of the above—andmore In fact, there is one such application for theFireBird SQL engine as well (IBWebAdmin), and evenone for Oracle (phpOracleAdmin) You can think of thisreverse engineering to be similar to the concept of
“reflection” as used in programming languages toreverse-engineer functions, classes, and objects in orderfor a program to “understand itself” and modify itsbehavior according to rules set by the programmer
23 $this -> relation = $relation ;
24 //$this->dbconn = $this->relation->dbconn; //share the
same database connection already established in the $relation
32 $valid_modes = array( “list” , “view” , “edit” , “add” ,
“insert” , “update” , “search” );
33 //view, list, edit, etc
34 if( in_array ( $mode , $valid_modes ))
44 //if mode is not ‘list’, it is implied that we
are in single-record view/edit mode
45 $this -> gui = new HTML_QuickForm ( { $this ->
rela-tion -> relname } , ‘POST’ );
56 function prepare ()
57 { 58
59 $this -> metadata = $this -> relation -> get_metadata ();
73 if( class_exists ( $classname ))
75
76 //compose column types in here
77 $this -> data [ $colname ] = new $classname ; 78
82
83 //default to char domain
84 $this -> data [ $colname ] = new rel_text ; 85
92 function render ()
93 { 94
95 $this -> relation -> do_select ();
Trang 13The more advanced ANSI-compliant systems such as
PostgreSQL have a very easy way to query metadata
through SQL (in PostgreSQL you query tables and
views in the iinnffoorrmmaattiioonn sscchheemmaa schema/namespace)
Armed with the tools above to extract metadata, we
can easily construct a very basic system to present an
example of these ideas: first, we create a basic
“inter-face” class called RReellDDoommaaiinn, then a class for each
domain/datatype—for now, we’ll limit ourselves to
RReellIInntt, RReellFFllooaatt, RReellCChhaarr, RReellTTeexxtt (Listing 2 - found in
this month’s code package) Next, we create a class
called RReellaattiioonn (Listing 3 - found in this month’s code
package), which will be composed of all domain
objects needed for any specific relation It also
incorpo-rates whatever methods are needed to extract
metada-ta from the given relation
Now, this is one aspect of how to combine an
object-oriented application framework with a relational
data-base system It deals with your datadata-base at the scopic level What about dealing with your database onthe macroscopic level? What if you could just “throw”
micro-a tmicro-able nmicro-ame micro-at micro-a certmicro-ain clmicro-ass or group of clmicro-asses, micro-andhave the application just read the table metadata,instantiate the right objects for each datatype in a col-umn, and automatically build your form? If this soundslike a too-good-to-be-true theoretical approach, justthink about it a moment: if you have a class for everydatatype, as well as classes to handle all the “mechani-cal” aspects of connecting to the database, querying,retrieving data, and so on, then all you need is a class
or set of functions for retrieving table/view metadataand some methods for tying these classes together into
a logical interface for the database Finally, we will have
a class called RReellGGuuii (Listing 4) to handle the displayand user interaction RReellGGuuii can inherit from someexisting classes, such as PEAR’s HHTTMMLL QQuuiicckkFFoorrmm, andHHTTMMLL TTaabbllee (and many additional helpful PEAR classes,
if you wanted it to) The whole idea here is that yourentire application can pass every database interactionthrough a dispatch file that looks essentially like the oneyou see in Listing 5, with the classes in the listings men-tioned above In addition, the code in Listing 6 tiesthem together as required files Of course, as I men-tioned earlier, PEAR’s HHTTMMLL TTaabbllee and HHTTMMLL QQuuiicckkffoorrmmare required
Briefly, here is what is going on in these files:
• When a browser request is made to Listing
5, at a minimum, the GET parameters forrreellnnaammee and mmooddee need to be passed as part
1 <?php
2
3 /* file: relpage.php */
4
5 include ( ‘./relfiles.php’ ); //include Domain.php, all
datatypes, and Relation.php
31 $gui -> set_mode ( $_GET [ “mode” ]); //valid modes are “list”,
“view”, “edit”, “add”, “insert”, “update’, “search”
Trang 14capa-of the URL This tells the program what
rela-tion to deal with, and how we want to
inter-act with the relation Valid modes (for now)
are lliisstt, vviieeww, eeddiitt, and sseeaarrcchh In “list”
mode, the table will be queried, and the
data output as rows
• When the user clicks an “edit” link on one of
the rows, the page re-draws itself in “edit”
mode, using URL-encoded arguments
passed in the link to provide enough
infor-mation for the WWHHEERREE clause in SQL A form is
then drawn, based on the relation metadata(column definitions) and the values for eachcolumn in the fetched row The user canthen edit the row and submit the new val-ues
To look a little deeper, the code in Listing 5 first tializes a new RReellaattiioonn object, based on the rreellnnaammeeparameter, and then passes a database connectionidentifier to it The Relation object prepares the meta-data for the given table/view Then, the code initializes
ini-a new RReellGGuuii object ini-and pini-asses the RReellini-aini-attiioonn object to
its constructor The appropriate mode
is passed as well, so that rreellGGuuii canautomatically know how to display thedata If the mode is lliisstt, for example,then the page looks like Figure 1 If themode is eeddiitt, RReellGGuuii automaticallyknows to create an editable form (asyou can see in Figure 2)
Inside Listing 3, you will see that,after extracting the basic metadatawith ppgg mmeettaa ddaattaa(()), we loop throughthe basic information to first create therelated object for each domain—andthen run some more sophisticatedqueries in PostgreSQL to get furthermetadata We take advantage of PHP’svariable classname calling on lines 68and 75 of Listing 4 to create ourdomain/datatype objects, thus allow-ing RReellGGuuii to derive hints on presenta-tion, and other aspects of the GUI Ofcourse, it is clear that we could do thiswithout creating the custom RReellDDoommaaiinnclasses, but then we would lose much
of the ability to add extra behavior todifferent column types To further illustrate the idea of how we can affect any area of the system through this, uncomment $$tthhiiss
>>sseettCCssssSSttyyllee((aarrrraayy((‘‘ccoolloorr’’==>>‘‘rreedd’’))))
in the rreell iinntt class stored on line 43 ofListing 2 Now, any integer type col-umn will display in red (the new stylewill be added to the fourth parameter
of HHTTMMLL QQuuiicckkffoorrmm’s AAddddEElleemmeenntt call inListing 4) There are many more thingsthat can be added this way, if you want
to play around with this concept,including additional HTML attributes,Javascript event handlers, and so on
What About MySQL?
You might be wondering how you canimplement these concepts if you are
F
FE EA AT TU UR RE E Object-oriented vs Relational Part II
Figure 1
Figure 2
Trang 15using MySQL While it is true that MySQL offers far less
functionality, lacking views, constraints, and domains,
than other DBMSs, it is precisely our sort of framework
that can help overcome some of these difficulties For
example, if you exercise a certain amount of discipline
in table design, you can “fake” domains by naming
columns after PHP classes you have created, and use
the column names as you reverse-engineer your tables
This way, if you have a column named “zipcode”, you
can assume that it corresponds to your rreell zziippccooddee
class in PHP Also, you could compensate for the lack of
views by creating a class that maintains a lookup table
with a list of names, and associate them with stored
queries, and uses the metadata functions in the
RReellaattiioonn class to return all the column definitions for
these “views” Similarly, you could maintain a lookup
list of constraints expressed in PHP which apply to
cer-tain tables, column names, and so forth The same
could also apply even more to SQLite, or other
light-weight database engines It’s a win-win situation
Garbage Collection: A Few Final Notes
Of course, a perfectly valid complaint about this sort of
approach is “what about efficiency?” Don’t all these
extra classes and methods present a serious
perform-ance problem? It’s possible As a general rule,
hard-cod-ing can lead to increased performance, and that would
apply to how we build our forms and interact with the
database However, as usual again, this comes at the
price of flexibility and manageability (or “developer
performance”) Which is cheaper, computer
perform-ance or your performperform-ance as a programmer? If you
want these advanced capabilities but are worried about
performance consider three things: first, the code
pre-sented here is not optimized; there should be plenty of
ways—especially with PHP5—to get better
perform-ance Second, there are several good PHP optimization
systems, such as the Zend Optimizer and Zend
Accelerator, as well as the Ioncube Accelerator and the
PPEECCLL::::aappcc extension, for example, and Third, computer
hardware is really cheap these days It would probably
cost less than a week’s wages to upgrade a server
sig-nificantly in performance
Therefore, performance concerns notwithstanding, in
the end we have an interesting situation We are using
quite a few of the concepts of object-oriented
program-ming: inheritance, encapsulation, aggregation, and
composition, without once infringing on the database’s
handling of business logic Now I agree that this small
example of coding here is incomplete (it is up to the
reader, for example to implement the
insert/update/search modes), and the data
presenta-tion leaves much to be desired In order to really create
a seamless whole between the hardcore logic
manage-ment in the database and the interactivity/presentation
of the application layer, one would probably need ten
118 $escaped_args = urlencode ( serialize ( $row ));
//argumenst to uniquely identify a row
119 $this -> gui -> setCellContents ( $rownum , $colnum ,
“<a href= \”{ $_SERVER [ “PHP_SELF” ]} ?relname= { $this -> relation -> name } &mode=edit&arguments= { $escaped_args }\” >edit</a>” );
136 $this -> gui -> addElement ( ‘header’ , ‘’ , “Edit
{ $this -> relation -> relname } );
137
138 $row = $this -> relation -> fetch_row ();
139 140
141 foreach( $row as $colname => $colval )
143
144 $html_attribs = array( “value” => $colval );
145
146 //additional HTML attribs are set here
147 if( is_array ( $this -> data [ $colname
]-> css_attribs ))
149 $html_attribs = array_merge ( $html_attribs ,
$this -> data [ $colname ]-> css_attribs );
151 if( is_array ( $this -> data [ $colname ]-> css_class ))
153 $html_attribs = array_merge ( $html_attribs ,
$this -> data [ $colname ]-> css_class );
155
156 //set max size attribute for textboxes
157 if( $this -> metadata [ $colname ][ ‘len’ ] > 0 )
174 } Listing 4: Continued from page 11
Trang 16times as much code as we have here This article,
how-ever, provides a basic prototype on how to handle this
sort of thing Again, PEAR can come to our rescue in
handling more sophisticated presentation and
interac-tion needs, with such classes as the following:
With these classes and the concepts presented in this
article, one could construct a very sophisticated set of
tools, not only for an application framework, but even
for an application development framework Think about
the possibilities of creating something what would be
like the web-based version of commercial systems like
Access, Paradox, or FileMaker Pro In one sense, our
tools could be even better, because the forms could
correctly adjust themselves to changes in the database,
which is something even the commercial tools
men-tioned above don’t really handle properly Where this
sort of approach can really shine, though, is in the ation of large enterprise applications, where theremight be several development teams, database admin-istrators, and sysadmins Imagine being on the phonewith the database administrator saying “sure, go aheadand make that change, then see what the form lookslike” and wondering what the look on his face looks like
cre-as he hears you speaking!
F
FE EA AT TU UR RE E Object-oriented vs Relational Part II
About the Author ?>
To Discuss this article:
http://forums.phparch.com/181
Rick Morris heads application development for MOS Imaging Systems in Miami, Florida (w www.mos.us s, w www.netcompass.us) He lives near Fort Lauderdale, Florida with his wife, 2 children, and the world’s laziest cat.
Available Right At Your Desk
All our classes take place entirely through the Internet and feature a real, live instructor that interacts with each student through voice or real-time messaging.
What You Get
Your Own Web Sandbox Our No-hassle Refund Policy Smaller Classes = Better Learning
Sign-up and Save!
For a limited time, you can get over $300 US in savings
just by signing up for our training program!
New classes start every three weeks!
http://www.phparch.com/cert
Trang 18Most XML generators are desktop applications—you
can drag-and-drop beautiful GUI nodes to build a DOM
document The XML generator introduced here is a
web application All the richness that you can find in a
desktop application is absent: the form only refreshes
upon submit, a lot more code is needed to make a
dynamic UI, HTML cannot support ‘complex’ data
structures like DOM, the browser cannot maintain
state, and so on Would a web XML generator
imple-mented in PHP be able to overcome all these
con-straints?
This generator was developed in the Infospheres Lab
at the California Institute of Technology to help users
generate state/transformation files for a crisis
manage-ment system The states inside the system are described
by XML files During an event, an agent changes its
state in ways described by XSL files For more details
about the crisis management system,
you can refer to the Infospheres web site at
w
www.infospheres.caltech.edu Making this XML generator
a web application has the advantage of being
light-weight—the client only needs an Internet connection
and a browser to use the service, thus it is platform
independent The server can also keep track of all the
files generated and save copies As with all web
appli-cations, efficiency is always the first priority to ensure
performance and reduce server workload
Let’s understand how it works by looking at a fire
accident scenario The initial state is ‘at peace’: state
name – normal; dead – 0; injury – 0; police – sleep; fire
station – sleep; and so on By putting all these values
into the generator (Figure 1), the corresponding XMLfile (Figure 2) is generated A message will be delivered
to the system when a fire breaks out, indicating the ‘fireagent’ should change its state The transformation rulefor this transition (e.g.: if the number of injuries stated
in the message is greater than four, the state nameshould change to ‘critical’) is specified in the XSL gen-erator (Figures 3 and 4) to generate the correspondingXSL file (Figure 5) The flowchart of the entire genera-tor is shown in Figure 6 As you can see, different XSLfiles will be invoked upon different events; for example,hhaannddlleettiimmeeoouutt xxssll will be invoked during timeout
UI that represents a changing datasetwith complex data structure
Initially, there are only four nodes under the root node
in the XML generator (Figure 7) A new input form ismade when the user modifies this structure (Figures 8and 9) The user interface is dynamically generatedafter every refresh/submit, based on the different
‘states’ (which consist of datasets) In addition, we have
to maintain ‘state’ change, which is based on the vious ‘state’ and the user’s modifications You shouldimmediately think of MVC (Model/View/Controller)
Code Directory: xmlgen
REQUIREMENTS
Developing a UI that manipulates large data sets is difficult Developing a UI dynamically upon user request is even more difficult This article aims to discuss the difficulties in developing a complex UI, demonstrated by the XML/XSL genera- tor made in the Infospheres Lab at the California Institute of Technology Examples of how to generate JavaScript dynam- ically at run time and how to represent a complex DOM tree with simple HTML data structure will also be shown Furthermore, the article will discuss the optimization of input validation Several error checking/correction algorithms will
be demonstrated This application is developed in PHP5, with extensive use of the new XML library.
Trang 20devel-here: the Model encapsulates the
‘states’; the Controller interprets theuser’s input, modifies the ‘states’ in theModel and chooses a new View; theView generates the UI based on thedatasets in the Model (Figure 10) Themain focus here is the datasets:
in order to make an efficientModel/View/Controller, the datasetshould be easy to manipulate Thereare already many articles about theMVC design pattern; you can refer tothe book Design Patterns by ErichGamma, Richard Helm, Ralph Johnsonand John Vlissides or to Jason Sweat’sarticles that have appeared on thepages of php|architect for more infor-mation
By just looking at the form, it seemsthat appending a child is as simple asadding one more row to the table It is,indeed, easy to manipulate a table—but this is only half of the picture Thistable actually represents a DOM treeand the rows are the child nodes at dif-ferent levels (you can see in Figure 11how the node level is indicated in theinput table) Thus, the dataset should
be a DOM document, with its structurespecified by the user The problem aris-
es that HTML does not support plex data structures like DOM, andthere is no way to POST a DOM node.The ‘most complex’ data structure sup-ported by HTML POST is an array Insolving this problem, we retrieve theuser’s input in such a way that the itcan be mapped to the DOM documentinside the Model
com-Even if you ignore the previous lem, imagine how complicated itwould be to generate the HTML inputtable from a DOM document.Therefore, let’s look at the problem inanother way: as mentioned, the mostcomplicated data structure supported
prob-by POST is an array; is it possible that
we can switch the dataset from a DOMdocument to an array? This may seemquite difficult, but PHP makes it less so.PHP is a scripting language, whichmeans no compilation is needed Itsupports many more powerful opera-tions on arrays than most compiled lan-guages, such as the ability to changethe size of an array at run time and bet-ter support for associative arrays An
Trang 21XML structure like the one in Figures 12and 13 can be represented by an array
as shown in Figure 14 In storing thenodes’ values to generate a new file orform, variables with names like
$$aattttrriibbuuttee 22, which can easily bemapped to the array, are used for theattribute of the second child of the rootnode This is necessary, as the arraycannot store the values and structure atthe same time (you can easily deter-mine this by looking at the ‘parentnode’ in the array) After a POST, thevalues can be retrieved simply as
$$HHTTTTPP PPOOSSTT VVAARRSS [[$$vvaarriiaabbllee nnaammee]], inwhich the variable names can beassigned when we loop through theDOM-structure-array by using the arraykeys This approach solves two prob-lems at the same time without a com-plex algorithm: it is much easier to gen-erate the input table from an array (thatrepresents the structure) and variables(that store the node value) (Figure 15—HTML of input table); both simple vari-ables and arrays can be POSTed to noti-
fy the server of the changing structureand node content The algorithm forgenerating the XML file and retrievinguser input will be described in the fol-lowing sections, when we discuss theView and Controller As we will see, this
‘data structure’ also helps improve ciency
effi-Arrays in PHP are more useful than inother languages, since the structure can
be changed during runtime You caneasily devise a program that utilizesarrays, like, for example, a computerpurchasing application Let’s apply theMVC design pattern again: the Model isinitialized with all the computer modelsavailable; based on the Model, the Viewgenerates an input form to accept pur-chasing information for each computer.When the form is submitted, theController interprets the input and noti-fies the Model about this additionalinformation Then, based on thechanged Model, a new View selected
by the Controller generates the tion form or another more complicatedinput form An array is used herebecause it can simplify the mapping between the purchasinginformation/other more complex data
valida-Figure 13
Figure 14
Figure 15
Figure 16
Trang 22and each computer, as demonstrated in Figures 16(array with computer models), 17 (array with buyer’sname), and 18 (array with extra hardware) This map-ping is not restricted to be a one-to-one relationship;multiple-to-one is also possible by using nested arrays.This is only possible if we can change the array size atrun time, because the amount of information is uncer-tain This helps a lot in terms of efficiency, because nosearching is needed during mapping and most algo-rithms that are based on this ‘data structure’ can be fin-ished in time linear with respect to the number of items
in the arrays The same approach is applied in makingthe XSL generator: the Model is initialized with theschema of the XML file and the corresponding transfor-mation rules are stored in arrays as mentioned above
In dealing with a changing dataset, the MVC designpattern is the only choice for a web application On theother hand, we need to take care of several thingswhen we use a certain way to store complex data: theefficiency of manipulating the data, the ease of gener-ating a user interface from the data, whether HTML isable to transmit those data, the ease of performing
8 $this -> statement = $this -> table -> tableStart ( , 4 );
9 $this -> statement = $this -> table -> rowStart ();
10 $this -> statement = $this -> table -> tableHeader ( “Node Level” , 1 , 1 );
11 $this -> statement = $this -> table -> tableHeader ( “Tag name” , 1 , 1 );
12 $this -> statement = $this -> table -> tableHeader ( “Defualt value” , 1 , 1 );
13 $this -> statement = $this -> table -> tableHeader ( “Attribute” , 1 , 1 );
14 $this -> statement = $this -> table -> tableHeader ( “Attribute value” , 1 , 1 );
15 $this -> statement = $this -> table -> rowEnd ( true );
16 $this -> file = $bean -> getValue ( $bean -> getName ());
17 $type = $bean -> getValue ( “type” );
18 if ( $type == 1 ) //special names for different files
31 $this -> xmlBuild ( $this -> info , $bean , “_” , $this -> dom );
32 $this -> dom -> save ( $filename );
33 $this -> statement = $this -> table -> tableEnd ();
34 $this -> statement = “<br><br><font size=\”3\” face=\”Verdana, Arial, Helvetica, sans-serif\” color=\”#9966FF\”>Agent name: “ ;
35 $this -> statement = $this -> expression -> drawName ( $this -> file , $filename );
36 $this -> statement = “</font>” ;
37
38 $string = file_get_contents ( “files/agents.dat” );
39 $array = explode ( “,” , $string );
Trang 23error checking/correction on the data (which we will
look at in next section), and so on As arrays in PHP are
comparatively a lot more flexible than in other
lan-guages, we should try to make good use of them
Generating the UI/file
According to the MVC design pattern, the View is
responsible for generating the user interface/file The
XXmmllBBuuiilldd class in the XML generator belongs to the
View, which constructs the file based on the XML
con-tents specified by the user in the Model (Listing 1) It is
very similar to the BBuuiilldd class, which constructs the user
interface for retrieving the XML file content The file is
generated by calling the xxmmllCCrreeaattee function, which
invokes the recursive function xxmmllBBuuiilldd to build the
‘real’ XML document and draw the checking table As
you can see, the running time is linear in the number of
nodes, which is as efficient as we can get Two design
patterns are employed in drawing the checking table:
Bridge and Command
Class XmlBuild only states the logic
of how to construct the table, while the
implementation of the actual drawing
is delegated to an object instantiated
from class Table The Bridge pattern is
applied; this decouples the logic and
implementation in such a way that
changing either one will be easy For
desktop applications, the biggest
bene-fit of employing the Bridge pattern is
portability; different widget
implemen-tations for different platforms, like
Windows, Mac OS and X11, are
encap-sulated in classes that inherit from an
abstract base class WWiinnddoowwIImmpp By just
programming on the abstract base
class, we can specify the construction
logic for the UI on all platforms When
switching platforms, we only need to
replace the object for implementation
and the logic will stay the same Based
on the same principle, the Bridge
pat-tern in a web application enables us to
change the implementation of the UI
without modifying the logic, making a
switch from HTML to XHTML, for
example, quite easy (Figure 19) More
importantly, the UI in a web application
changes even more often than in a
desktop application What most web
applications do is more or less the
same: filling forms, saving or searching
records, and so on What makes a web
application outstanding is the user
interface—therefore, every developer
should try to make the interface
imple-mentation as flexible as possible
When the ddaattaaTTaabbllee function is called to draw a cell,
$$tthhiiss >>eexxpprreessssiioonn is passed as parameter This isemploying the Command pattern: the action of draw-ing the content in the table cell is encapsulated in theobject, $$tthhiiss >>eexxpprreessssiioonn in this case (Figure 20)
$$tthhiiss >>ttaabbllee is the ‘invoker’ that invokes the drawingand $$tthhiiss >>eexxpprreessssiioonn is the ‘command’ that knowshow to perform the drawing The action of drawingcan thus be parameterized before any action takesplace, as in Listing 2, where the node value is specified.This pattern is helpful in decoupling the objects thatinvoke the operations (table) from the objects thatknows how to perform them (expression) In addition,
it is easy to add new invokers or commands by classing In the original Command pattern, the invokerscall the ‘execute’ function in the command repeatedly
sub-to perform the action A restriction arises: only onemethod, ‘execute’, can be called by the invoker Themost straightforward solution is to perform condition-
1 <?php
2 /**
3 * Setup the data of the checking table
4 * (parameterized the action of drawing the checking table before drawing)
5 */
6
7 function setData ( $result , $mother , $key , $child )
9 $this -> tag = $result [ ]; //node tag
10 $this -> attr = $result [ ]; //node attribute
11 $this -> attrv = $result [ ]; //node attribute value
Trang 24ing in the invoker (perhaps based on the input eters) to decide what function to call on command.However, this exposes the command object interfaceand renders the Command pattern ineffective
param-Another approach is to pass in function handlers It iseasy to create a function handler in PHP because it isonly a string containing the function name, and thefunction can be called by $$oobbjjeecctt >>$$ffuunnccttiioonn nnaammee(())(an example is ddrraawwLLeevveell in Listing 3 to print the nodelevel, called by the ttaabblleeDDaattaa function in Listing 4),which does not involve any ‘complex concept’ likefunction pointers in C and C++ In this case, the invok-
er is completely ignorant about the command object The main difference between rendering the file andthe UI is that we have to perform extra error checkingwhen the former is being handled For example,
F
FE EA AT TU UR RE E Developing a PHP - XML Generator
1 <?php
2 /**
3 * Draw the level of the node by comparing the last node
with the same level
8 $statement = “<TD COLSPAN=$colspan ROWSPAN=$rowspan>” ;
9 $statement = $expObj -> $function ();
Trang 25adding a node without appending it to any parent in aDOM tree is invalid In this case, the node is valid when
we merely look at the node content, but when we look
at the tree structure as a whole, the node becomes anerror This kind of checking is unnecessary if we storethe values in a DOM document, but we store them sep-arately here Thus, we need the functions ggeettCCNNooddee
(Listing 5) and ggeettMMNNooddeefrom Listing 2 These functionsare responsible for error checking and for rendering thechild or parent node using the DOM functions in PHP5.The DOM functions throw exceptions for invalidexpressions, thus ensuring the correctness of the nodecontent In addition, ggeettCCNNooddee(())and ggeettMMNNooddee(())returnNULL when reading a node without tag names; thiscauses all the node’s children to be neglected becausethey do not have a parent With the checking per-formed by the Controller when appending a number ofchildren to the tree, the validity of the file can be guar-anteed
However, there are cases where checking cannot beaccomplished by just looking at the current value, butother entries also need to be taken into account This isinefficient because some values may be visited multipletimes for checking and the running time may becomeexponential If we apply this method to the XSL gener-ator, it does not even work—for example, if we try toidentify whether a node is a vvaalluuee ooff node or a textnode by looking at the node value (vvaalluuee ooff node inFigure 21; tteexxtt node in Figure 22) This is error pronebecause an expression like ////lleevveell++11 seems to be avvaalluuee ooff node, but may actually be a text node (using
a strange expression) The most robust solution is torequire the user to specify the types and store them inanother array, which again can be mapped to the orig-inal set of data easily This approach can be furtherapplied to mark whether a field is used, whether thenode is a child or parent, and so on Although moreresources are needed, this ensures that no node is visit-
ed more than once for error checking In addition, ithelps simplify the algorithm for building UI/file as allrelated information can be found easily without search-ing (Listing 6)
Input processing
The Controller is responsible for handling the user’sinput according to the MVC design pattern In order todesign an efficient Controller, we must first understandwhat data is transmitted to the server in a PHP webapplication
The GUI in a desktop application usually has eventhandling to invoke programs, for example MFC orWindow forms in NET, and so on However, in a webapplication, there is no way that you can ask a text box
to invoke a function from the server The only way forusers to communicate with the server is by submittingthe whole form, which means the server will be sent all
1 <?php
2 /**
3 * Identify the default value and save it
4 * Inside a foreach loop with $i, $j counting the level of
16 $defaultValue = trim ( $value [ $i ][ $j ]);
17 for ( $k = 0 ; $k < count ( $attribute [ $i ]); $k ++) //set
36 $text = $this -> dom -> createTextNode ( $this -> element );
37 $node -> appendChild ( $text );
38 return array( $node , array( $this -> tag , $this -> attr ,
$this -> attrv , $this -> element ));
40 }
41 ?>
Listing 5
Trang 27the GUI information However, the server usually does
not want that much—fields that have not been
modi-fied do not contain any useful information Sending all
of them to the server wastes bandwidth and adds extra
workload to the server, as it needs to search for
specif-ic information If the data is sent in this way, it is
diffi-cult to develop an efficient Controller, as the
informa-tion to be processed will be overwhelming Thus,
before we design the Controller, let’s see what we can
do to restrict the amount of data sent
Let’s look at the XSL generator again (Figure 23)
When we click “Go!”, we only want to submit the
‘number of items’ for that particular table Only that
number is needed in drawing a new table, so sending
any more data would be a waste The only solution is
to make a form that only contains the ‘number of
items’ and the “Go!” button; thus, there will be
multi-ple forms in a single page However, this method does
not work when the input fields are interleaved, as the
contents in a single form must be grouped together
This is also true for the XSL generator; the input fields
of XSL node values are interleaved with the ‘number of
items’ text boxes (Figure 24), thus the input fields for
XSL nodes cannot be put in the same form
We can, however, use JavaScript to group these
entries In this example, these input fields actually do
not belong to any form The values in the fields are
extracted by JavaScript during submit and placed into
another separate form, in the corresponding hidden
fields (figure 25) The caution: the JavaScript fails if it
operates on non existing fields Thus, the JavaScript
must also be dynamically generated if the form is
dynamically generated; we discuss this in the next
sec-tion
We are able to limit the amount of data sent in the
above example, so the Controller does not have to
search for the information However, in some cases,
most data in the form are needed and therefore it is
wasteful to write so much extra code to restrict the
amount of data sent In these situations, we need to
fig-ure out how to process the data efficiently Let’s look at
the XML generator as an example When we append
children to a node, all data in the form except the
“number of children to append” for other nodes are
needed (Figure 26) The user’s input will be in one of
the “number of children to append” fields and we need
to search that out One way is to walk through all of
them and search for the one that contains a number
The running time here is linear in the number of nodes
Can it be more efficient? Yes, when we can utilize the
data sent The button data is also sent at submission
time Interestingly, when a button name is specified as
an array (e.g button[0][0][1][0]), the submitted data is
an array as well (Figure 27) We can find out what
but-ton the user has pressed and retrieve the corresponding
“number of children” without visiting all the input
fields Listing 7 shows how to find the node and
modi-1 <?php
2 /**
3 * The recursive function to find which button is pressed
4 * and the number of children to append
13 $newAlready = $already ”_” $key ;
14 $newInput = $input [ $key ];
15 $deepChild = $child [ $key ];
16 $get = $this -> findChild ( $value , $deepChild ,
$newInput , $newAlready , $HTTP_POST_VARS );
17 if (! $get ) //wrong input
Trang 28fy the “DOM array tree” The running time becomeslinear in the depth of the tree, which is much more effi-cient In addition, we perform error checking to discov-
er whether the user has entered any malformed input(like negative numbers or letters) The original ‘DOMarray’ remains untouched in such a case
Dynamic UI
As mentioned in the last section, JavaScript can helprestrict the amount of data sent to the server In addi-tion, it can produce a truly dynamic user interface InJavaScript, the change in user interface is performed bythe browser instead of the server More specifically, wecan specify a function and ‘relate’ it to a control so thatthe browser will invoke the function when that
F
FE EA AT TU UR RE E Developing a PHP - XML Generator
1 <?php
2 function toString ( node ) {
3 var str = “” ; // the var keyword makes str a local
21 } else if ( dataType == “var” ) {
22 if ( getSelectedValue ( node ) != “NULL” ) {
23 if ( getSelectedValue ( node ) == “default” )
36 if ( getSelectedValue ( node ) == “NULL” ||
getSelectedValue ( node ) == “null” ) {
51 } else if ( dataType == “edit” ) {
52 str = node firstChild value ;
10 function newOption(value, text) {
11 var option = document.createElement(“option”);
13 for ($j = 0; $j< count($this -> operand); $j++) {
33 return $statement1;
35 ?>
Listing 10
Trang 29control is triggered For more detail see
h
http://www.w3schools.com/, where you can find lots of
good tutorials on JavaScript Let us examine the XSL
generator to see how JavaScript can produce a
dynam-ic UI This is the expression generator (Figure 28) It can
generate simple expressions as shown in Figure 29, or
complex expressions as shown in Figure 30 Thedynamic UI part is in adding and removing terms withparentheses, changing the type of expression (Figure31) and switching between self-defined values and sys-tem-provided variables (Figure 32) In this example, notonly is a dynamic UI rendered, but bandwidth is alsosaved and error checking is performed; instead of send-ing the menu values one by one, they are combined as
a string and the expression is checked for validitybefore sending to the server by the ttooSSttrriinngg functionshown in Listing 8)
However, there is no formal way to generate theJavaScript using PHP at runtime We need to do sobecause the content of our client-side script cannot befixed when the data is encapsulated in the PHP script
In this example, the number of input fields that theJavaScript needs to operate on is not fixed until theXML file is parsed If the scripting mechanism is care-lessly implemented, everything turns into a big bowl ofspaghetti code, and changing either the server- orclient-side scripts becomes extremely difficult
Therefore, let’s solve it step by step The first thing to
do in separating the JavaScript code is to encapsulate itinto PHP functions and put it into a single class, which
I called CCoommmmoonnJJSS Some functions can be hardcoded(Listing 9), while others need to get parameters fromthe function callers (Listing 10) Next, we separate thecode and define a class to call the functions, calledEExxpprreessssiioonn here EExxpprreessssiioonn somehow gets all parame-ters required by the CCoommmmoonnJJSS functions from differentparts of the system, and calls the functions fromCCoommmmoonnJJSS Thus, the CCoommmmoonnJJSS interface is only exposed
to EExxpprreessssiioonn The Bridge pattern is again applied: theimplementation part is in CCoommmmoonnJJSS and the logic part is
in EExxpprreessssiioonn; this way, changing either of those will beeasy (in most cases, we are just changing the imple-mentation part)
So far, so good However, there are two problems:
• What happens if there is more than oneobject that wants to call the JavaScript func-tions? These objects may call the same func-tion twice, passing different parameters, andthe JavaScript will crash
1 <?php
2 /**
3 * Draw the JavaScript header
4 * Collect function handlers as well as parameters
5 * merge them before calling the function from $js
31 $statement = $this -> js -> generate ( $para , $boo );
32 $statement = $this -> js -> footer ();
8 $obj =& $booObject -> getDataSet ();
9 $name = $obj -> getDataName ();
Trang 30• How can EExxpprreessssiioonn get the parameters
from the whole system? If this is
implement-ed carelessly, EExxpprreessssiioonn may know about
the interfaces of most parts of the system,
and we would need to rewrite EExxpprreessssiioonn
whenever more data is added
The solution to the first problem consists of
introduc-ing a new class, JJSSDDrraawweerr, to be the only function caller
of CCoommmmoonnJJSS (instead of EExxpprreessssiioonn) It retrieves function
handler/parameters from different objects and merges
them before calling the functions from CCoommmmoonnJJSS
(Listing 11) All functions are called exactly once The
function handlers (Listing 12) are again only strings
that contain the function names In this case, no
mat-ter how many objects need to call the JavaScript tions, it can be done through JJSSDDrraawweerr, as long as theseobjects have the same functions to provide the functionhandlers and parameters
func-The solution to problem number two is to require thesystem to put data in a centralized object, namedDDaattaaSSeett in my case This way, EExxpprreessssiioonn will be ‘fed’
by DDaattaaSSeett for the parameters and remain unaware ofthe rest of the system In the previous case, ifEExxpprreessssiioonn asks the system ‘explicitly’ for data, it has to
be rewritten when more more data from other parts ofthe system is included However, this is not necessarywith DDaattaaSSeett; storing all data collectively in this struc-ture also allows passing the data from page to page byserialization and session mechanisms (Listing 13), and
F
FE EA AT TU UR RE E Developing a PHP - XML Generator
51 $new = $this -> file ”,” $string ;
52 file_put_contents ( “files/agents.dat” , $new );
63 //$info is the structure-array
64 //$bean contains XML data
65 //$mother is the strings indicating node level
66 //$motherNode is the parent DOM node
72 $this -> domWriter -> setData ( $bean , $mother , $key , false );
73 $result = $this -> domWriter -> getMNode ();
74 if ( $result != NULL )
76 $motherNode -> appendChild ( $result [ ]);
77 $this -> expression -> setData ( $result [ ], $mother , $key , false );
78 $this -> statement = $this -> table -> rowStart ();
79 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawLevel” , 1 , 1 );
80 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawTag” , 1 , 1 );
81 $this -> statement = $this -> table -> tableInfo ( “N/A” , 1 , 1 , NULL );
82 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawAttr” , 1 , 1 );
83 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawAttrV” , 1 , 1 );
84 $this -> statement = $this -> table -> rowEnd ( true );
85 $newMother = $mother $key ”_” ;
86 $this -> xmlBuild ( $value , $bean , $newMother , $result [ ]);
92 $this -> domWriter -> setData ( $bean , $mother , $key , true );
93 $result = $this -> domWriter -> getCNode ();
94 if ( $result != NULL )
96 $motherNode -> appendChild ( $result [ ]);
97 $this -> expression -> setData ( $result [ ], $mother , $key , true );
98 $this -> statement = $this -> table -> rowStart ();
99 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawLevel” , 1 , 1 );
100 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawTag” , 1 , 1 );
101 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawValue” , 1 , 1 );
102 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawAttr” , 1 , 1 );
103 $this -> statement = $this -> table -> tableData ( $this -> expression , “drawAttrV” , 1 , 1 );
104 $this -> statement = $this -> table -> rowEnd ( true );
Trang 31introduces one more way of storing data: storing the
serialized DDaattaaSSeett in a file
Review
There are many more constraints in implementing the
user interface for a web application than for a desktop
application As we walk through examples of how to
display complex data from changing datasets, how to
generate a UI, how to process users’ input and how to
produce a dynamic UI, we see that the approaches are
completely different Besides functionality,
perform-ance and flexibility are also important: the server will be
easily overloaded if the code is inefficient, and UI of
web applications changes often so the cost of
redevel-opment should be minimized
The XML/XSL generator can be found online at
h
http://unity.cs.caltech.edu/~mpchau13/start.php It is still
in the prototype stage—and you are, of course,
wel-come to report any bugs you encounter
Acknowledgements
I would like to thank Prof K Mani Chandy and Dr
Daniel M Zimmerman for their unfailing guidance and
support, and for the freedom to conduct the research
Thanks also to Mr Elliott Michael Karpilovsky, Mr
Jonathan Lurie, Mr Shaun Lee and Mr Siu-on Chan fortheir valuable comments and advice This project isfinancially supported by the Hong Kong Chapter of theCaltech Alumni Association
About the Author ?>
To Discuss this article:
http://forums.phparch.com/182
Grace is a year-three undergraduate student at the Chinese University of Hong Kong, majoring in information engineering She earned her expenses by developing and maintaining over ten systems in PHP for the whole school, including all kinds of attendance record systems, as well as school project databases This XML generator is part of her Summer Undergraduate Research Fellowship at the California Institute of Technology.
Trang 33One of the changes introduced in PHP 5 in regard
to XML handling is a change in the underlying
library that is being used to parse XML
docu-ments
In PHP 4, the Expat library was used to parse XML
documents when the standard XML parsing extension
was used To ensure that the XML extension would be
enabled by default, the Expat library was bundled with
PHP, meaning that you’d always have the necessary
dependencies—the fact that the library had a
PHP-friendly license and was quite small helped cement this
decision Furthermore, new versions of the library were
far in between, making the job of ensuring that the
lat-est stable release was always bundled with PHP fairly
simple
While this convenience was nice, it did cause a
num-ber of problems First of all, bundled libraries are built
into PHP directly during the compilation process,
meaning that, whenever you wanted to upgrade the
library, you would need to recompile your entire PHP
build Moreover, if PHP was used as a module—with
Apache, for example—the library could end up
conflict-ing with another Expat library variant used by another
piece of software, such as an Apache 2 server You
could compile PHP by specifying an external Expat
library via the ——wwiitthh eexxppaatt ddiirr flag, but very few
peo-ple actually did so Another problem with Expat is the
fact that its development cycle was quite slow and new
functionality was very rarely, if it all, added, meaning
that the capabilities of the library were somewhat
lim-ited Other XML extensions, such as DOMXML used a
different XML parsing library, Libxml2, which meant
that you could end up having PHP use two libraries thatduplicate each other’s functionality—never a goodidea
Libxml2: The Swiss Army Knife of XMLLibraries
With the impending release of PHP 5, in order to unifythe underlying XML parsers, all extensions that workwith XML were made to use the Libxml2 library, which
is an XML C parser and toolkit developed for theGnome project This library is a very popular XML pars-
er and virtually every modern *NIX distribution has itinstalled by default It is being very actively developedand, consequently, supports all of the new andadvanced XML features, such as DTD validation, Xpath,HTML support, and so on After much talk on the PHPdevelopment list, the decision was made not to bundlethe library, since it is quite burdensome (as a sourcepackage, at least, it’s almost as large as PHP itself) andits frequent releases would make bundling it a mainte-nance nightmare However, because the library can befound on virtually any system (for Win32 builds, thelibxml2.dll file is included with PHP) this not much of aproblem and actually allows easy upgrades of thelibrary without having to recompile PHP, since thelibrary is linked dynamically
Libxml2 happens to support an Expat-emulation
by Ilia Alshanetsky
PHP: 5.x OS: Any
REQUIREMENTS
When most people talk about PHP 5, they tend to concentrate on the many improvements in the way it works with objects, which is certainly a significant component of the new release This often leaves equally important improvements, such as the changes made to the way PHP works with XML, neglected This article’s goal is to familiarize you with how XML is handled by PHP 5 and how these changes make working with XML much easier.
Trang 34mode, which makes it behave in an almost identical
manner to the original Expat library This means that,
for the most part, the behavior of the XML extension
based on Expat in PHP 4 is not different from the one
in PHP 5 The new library is significantly faster in
pars-ing XML documents, however, especially when DOM
trees are built This said, when using SAX, in some cases
the original Expat library will be a little faster, which is
why some people who only use Sax still can compile
the XML extension in PHP 5 against the Expat library by
specifying the ——wwiitthh lliibbeexxppaatt ddiirr configuration
direc-tive Keep in mind, however, that, since the Expat
library itself is no longer bundled, if you choose to go
this route, you will need to make sure that it is
separate-ly installed on your system before you configure and
compile PHP
The Traditional Way
The “oldest” way of parsing XML documents via the
XML extension—using the xxmmll ppaarrsseerr ** family of
func-tions—didn’t change much between PHP 4 and 5 The
only changes are caused by slight incompatibilities
between the underlying XML libraries, which, for the
most part, are fairly minor and hard to trigger and will
not, therefore, affect most users This parsing
method-ology uses the Simple API for XML (SAX), which is an
event-driven interface in which the parser invokes one
of several methods supplied by the caller “Events”
include recognizing an XML tag, finding an error,
encountering a reference to an external entity, or
pro-cessing a DTD specification The advantage of this
par-ticular approach is that it does not require you to have
the complete document in memory This is particularly
good for large XML files that would require immense
amounts of memory if they were loaded into memory
It also allows you to parse XML documents as you
receive them from external sources (such as an HTTP
feed) rather then having to wait for the entire
docu-ment to be retrieved before getting to the parsing
stage
Because the parser does not work with the entire
document, it cannot perform parsing optimizations
that result from knowing the document’s structure This
means that, for small XML documents that do not
require much memory, using DOM to create a DOM
tree would actually be faster
To handle the SAX events in PHP, you need to
speci-fy a function or a class method that will be used to
dle this particular event At minimum you need to
han-dle at least three events: tag start, tag end and tag data,
as shown in Listing 1
The parsing process does not return any data—the
job of collecting data and returning it in some way is
left to the event handler functions Those functions will
need to determine what tag they are operating on,
what event is being processed and use global variables
or class properties to store the data while the document
is being parsed—you can see an example of this inListing 2
Here, the ttaagg ssttaarrtt ssttaarrttfunction creates a rary array variable and stores the name of the currenttag, including its attributes (if available), into it It alsoinitializes the third array element, which later will beused to store the tag’s data If the tag contains anyattributes, they will be stored inside the $$aattttrr variable;these will be included in an array in which every ele-ment constitutes an attribute whose name is stored inthe key If no attributes are available, the variable willcontain NNUULLLL
tempo-Listing 3 shows the data handling function, whichsimply appends any data passed to it to the data ele-ment of our temporary array It is important to appendthe data, rather than to assign it directly, since if the
F
1 <?php 2
3 $x = xml_parser_create (); // initialize XML parser
4 // specify tag start and end handlers
5 xml_set_element_handler ( $x , ’tag_start_func’ , ‘tag_end_func’ );
6 // this function will handle the data inside the tag
7 xml_set_character_data_handler ( $x , ‘tag_data_func’ );
8 xml_parse ( $x , “xml_file.xml” ); // parse document
9 xml_parser_free ( $x ); // free memory
10
11 ?>
Listing 1
1 <?php 2
3 function tag_start_func ( $x , $tag , $attr ) {
4 global $tmp_data ; 5
6 $tmp_data = array( $tag , $attr , ‘’ );
7 } 8
9 ?>
Listing 2
1 <?php 2
3 function tag_data_func ( $x , $data ) {
4 global $tmp_data ; 5
6 $tmp_data [ ] = $data ;
7 } 8
9 ?>
Listing 3
1 <?php 2
3 function tag_end_func ( $x , $tag ) {
4 global $final , $tmp_data ; 5
6 if (isset( $final [ $tag ])) {
7 $final [ $tag ] = array();
14 ?>
Listing 4
Trang 35tag’s data is very large or contains new lines it may be
returned in portions Thus, appending ensures that all
of the data for the tag will be fetched, rather than just
the last portion
When an end of the tag is encountered, the XML
parser will call our ttaagg eenndd ffuunncc function, shown in
Listing 4 Here, we place the data inside the $$ffiinnaall
global variable, which at the end of the parsing process
will contain the data from the XML document The tag
name is used as the key of the return array and itself
points to an array of values, since a tag is likely to occur
more the once The value stored contains all the
attrib-utes of a tag and their value Once the data has been
stored, the temporary $$ttmmpp ddaattaa array is destroyed, so
that its values will not conflict with the next tag
When Simple and XML Meet
As you can imagine, this does not make for a very
sim-ple imsim-plementation, which is why very few developers
actually like SAX Unfortunately, in PHP 4 the
alterna-tive—that is the DOM extension—had, until very
recently, a variety of serious problems, which
prevent-ed it from being a true alternative to XML/SAX
Additionally, because PHP code is heavily involved in
the parsing process, it does not make for a very fast
parser, since every tag results in at least three PHP
func-tion calls So, it is hardly surprising that developers
spent the time needed to improve this process for PHP
5!
One of the new extensions designed specifically for
fast and simple parsing of XML documents is
SimpleXML This extension heavily relies on the new
object-oriented features of PHP 5 to make the process
of parsing XML documents as trivial as possible Unlike
the XML extension, this extension uses the Document
Object Model (DOM) approach to parsing documents
This means that, in order to process a document, the
entire contents of the document must be retrieved—
and only then will a DOM tree representing the
docu-ment be created in memory This is quite fast for small
documents, which don’t require too much memory
and can be quickly retrieved even when they are stored
on remote servers However, when dealing with an
XML document whose size is in the tens of megabytes,
this may become quite slow due to the significant
memory requirements Fortunately, not many people
encounter such large XML files, so for the most part this
is a perfectly acceptable limitation
Parsing a document with SimpleXML could not beany simpler (no pun intended) As you can see inListing 5, it only takes a single function call, which takes
a single parameter that contains the XML data to beparsed This data can come from a local or remote file
or even a text string
The return value of SimpleXML’s ssiimmpplleexxmmll llooaadd **(())
functions is an object that represents the supplied data.You can now access that data as if it were a regular PHPobject, with each XML field stored in a separate prop-erty of matching name The attributes become thearray keys of the XML field to which they belong to, asshown in Listing 6
In the event that there are multiple instances of a ticular field, you can use to ffoorreeaacchh(()) language con-struct to iterate through the XML elements as if theywere an array and retrieve the data in the form of anobject It should be noted that while ffoorreeaacchh(()) itera-tions will work, you cannot use most of PHP’s arrayfunctions on objects created by SimpleXML
par-In the example shown in Listing 7, another OO ture of PHP 5 is being used: while $$aa is actually anobject, SimpleXML implements ttooSSttrriinngg(()), whichallows you to “print” the object and get the value ofthe data stored inside it In PHP 4, this would outputsome useless text, completely irrelevant to the neededoutput This is one of the reasons why SimpleXML can-not be back ported to PHP 4, where the Zend Engine 1simply lacks the functionality this new extension needs.Another neat feature of SimpleXML is the ability toaccess a particular element of the XML document with-out having to iterate your way to it In fact, this can bedone in more than one way The simplest and fastest
fea-1 <?php 2
3 $s = ‘<xml><a>Value 1</a><b id=”1”>Value 2</b></xml>’ ;
4 $x = simplexml_load_string ( $s ); // parse XML string
5 echo $x -> a ; // will print value of <a> field, “Value 1”
6 echo $x -> b ‘id’ ]; // will print attribute of b field, “1”
7
8 ?>
Listing 6
1 <?php 2
3 $s = ‘<xml><a>Value 1</a><a>Value 2</a></xml>’ ;
4 foreach ( simplexml_load_string ( $s ) as $a ) {
5 echo $a ; // print value of element <a>
6 } 7
8 ?>
Listing 7
1 <?php 2
3 $s = ‘<xml><b><c><a>Value 1</a><a>Value 2</a></c></b></xml>’ ;
Trang 36approach consists of using indirect object references to
simply access the desired element from the DOM tree
The example that you can see in Listing 8 will make
PHP print the value of the second <<aa>> element, which is
contained within the <<cc>> element, itself a child of the
<<bb>> element SimpleXML is intelligent enough to figure
out that, when the array key is numeric, I am actually
attempting to access a particular element rather than
one of its attributes The one thing to be aware of is
that, if you access a non-exist element, SimpleXML will
not print any warning message—your output will
sim-ply be NULL Therefore, in order to verify that the
ele-ment exists, you should always use the eemmppttyy(())
con-struct Even if, for whatever reason, the value of the
ele-ment is blank, you’ll still have an object as the result,
meaning that eemmppttyy(()) will return false, indicating that
the element that you’ve tried to access does in fact
exist
XPath
Another way to retrieve a particular element from a
DOM tree is by using the XPath query language that
SimpleXML supports XPath is language—ratified by
W3C—for addressing parts of an XML document This
language allows accessing an XML document as if it
were a file system and each element were either a file
or a directory It also supports the ability of searching
for a particular element inside the document regardless
of its location
The example in Listing 9 will access the text contents
of the second <<aa>> element; please note that in XPath,
unlike what happens with PHP, the element count starts
from one and not zero The output of the xxppaatthh(())
method is going to be an array of matching entries,
unless nothing can be matched, in which case a
Boolean value of FFaallssee will be returned Each element
of the array is an object containing the value of the
matching element—in this case, the value will be
“Two”
As an alternative, you can try searching an XML
doc-ument for an element whose attribute value matches
the one you are looking for, as shown in Listing 10 In
this case, SimpleXML will use libxml2 facilities to search
for an <<aa>> element inside the document and isolate the
element (or elements) that contain the iidd attribute and
whose value is equal to 3 The one thing to remember
when using the XPath query language is that searching
through an XML document—especially a large one—is
not a very fast operation Therefore, if you know the
location of the data, it would be far more efficient to
reference it by hand from the DOM tree object
Aside from data retrieval, SimpleXML can also be
used to modify the existing XML documents However,
you can only modify existing elements and not add
new ones The process of modifying the data is quite
simple; all you do is assign an alternate string or integer
value to the property (element value) or the array key(attribute) The modified document can then bereturned as an XML string, as shown in Listing 11
The Document Object Model Extension
While SimpleXML cannot add new elements to anexisting document, you can convert SimpleXMLobjects to DOM-extension objects by calling the ssiimm pplleexxmmll iimmppoorrtt ddoomm function The DOM extension canthen be used to perform any number of modifications
to the converted object and, if necessary, convert itback to a SimpleXML object via the ddoomm iimmppoorrtt ssiimm pplleexxmmll function This is an advantage of having bothextensions use a DOM tree to represent the XML doc-ument while utilizing the same underlying library
This brings us to another new XML extension in PHP5: the DOM extension, which is a complete rewrite ofthe DOMXML extension that was available in PHP 4
The new extension, like SimpleXML, makes use of thenew PHP 5 OO features and addresses some of the lim-itations found in the older code, as well as introducingnew functionality Most importantly, it suffers fromnone of the problems that plagued the DOMXMLextension in PHP 4, such as memory leaks The newinterface makes it much simpler to work with XML doc-uments, which you can create, modify, join and evenvalidate The extension supports the ability to workwith HTML documents, even if they are not wellformed, which gives you the ability to easily parseHTML without writing a custom parser
While the DOM extension can be used to parse uments, the process is not quite as simple as it is withSimpleXML, which is why interoperability with the lat-
doc-F
1 <?php 2
3 $s = ‘<xml><b><a id=”1”>One</a><a id=”3”>Two</a></b></xml>’ ;
3 $s = ‘<xml><b><a id=”1”>One</a><a id=”2”>Two</a></b></xml>’ ;
4 $r = simplexml_load_string ( $s );
5 $r -> b -> a 0 ][ ‘id’ ] = 5 ; // modify attribute of 1st <a> element
6 $r -> b -> a 1 ] = “Three” ; // modify value of 2nd <a> element
7 echo $r -> asXML (); // print modified XML
8
9 ?>
Listing 11
1 <?php 2
3 $s = ‘<xml><b><a id=”1”>One</a><a id=”3”>Two</a></b></xml>’ ;