What's your idea of PHP best practices?
February 19, 2005 8:47 PM   Subscribe

PHP programmers: what would a well-laid-out PHP project look like to you? I'm a computer science grad student who's never used PHP for anything much and not in many years, but I now have an opportunity to write a small-to-moderate-sized site for somebody and thought I'd give PHP another go. I'm well versed in generally writing tasteful programs and I even have a pretty decent amount of experience with writing web sites using other technologies; what I'm really interested in is specifically how PHP programmers use the language in practice to make maintainable sites. For instance, what's the best way to separate content from HTML so it's easier to make site-wide HTML tweaks? What are the sorts of things that you wish someone had told you about how to build PHP projects?
posted by jacobm to Computers & Internet (10 answers total) 2 users marked this as a favorite
I try to put as much business logic into classes or files outside the page and then include them as necessary. Each directory usually has an include file in it that references every other file I need (e.g. www/myproject/thissection/ has an include.php that calls ../myproject.inc.php that includes all the handy libraries and classes the app needs). Usually ends up as a mess of references but means that each individual script can focus on one function. Unless the project is very small or trivial the business logic gets wrapped up in functions/classes and placed outside the webroot, to be included later, and each page that displays info just calls (member) functions. I try to stay away from making monolithic pages - if your index.php file has the entire app in it, it makes it hard to maintain later on. I make directories and try to limit each file's scope to one specific function (so for an app that has a modify, add, view, and delete function for a record there's 4 files). I find that alone makes things much easier, even if you do end up with a lot of files.

As someone who's had to maintain other people's code, I hate it when they put business logic in the HTML - not only does it make it a PITA to update the HTML, it's a pain to debug as well. Even if I'm not librarying or class-ifying the code all the important stuff (including database calls, storing results in arrays and all that) goes at the very top, and the HTML only gets enough PHP to make it work (like, a for loop that steps thru a previously-saved database result set).

For sitewide stuff, I usually take out the design that's been handed to me (usually made in Dreamweaver and therefore an abberation of horribly-formatted code), clean it up to "house style", and containerize it - split it into headers and footers and require_once them as necessary. If your designer designs to standards and is halfway intelligent about content flow (or you're good enough to come in and clean up afterwards) then technically you should never have to touch any design stuff in the HTML code, just edit the header and footer. There are also templating systems (Smarty, PHP Savant) you can employ to let your designers put the PHP in as they need to and then you just wrap it up with business logic.
posted by mrg at 9:05 PM on February 19, 2005

Addressing the last bit of your question, mysql holds the content, a UBB/phpBB style tagging system is used for formatting and a few basic php scripts in the form of a basic HTML template fetch the appropriate page from the database, covert the markup and produce the page for the browser.
posted by krisjohn at 9:07 PM on February 19, 2005

Identify the components that all of the pages on the site will have in common. This is usually along the lines of common header and footer content, and some sort of site navigation. Having done this, place all of the code to generate these components in their own php files. Then, for each page of your site, include them, using 'require'. This way, if you decide, for example, to change the title graphics at the top the page or copyright notice at the bottom of the page, modifying the component's file will propagate the changes to all pages of the site. Basically, it's a matter of don't repeat yourself: if some functionality is common to two or more pages, place it in its own file, and then include that file.

Also, if you're using style sheets, the html should be the content. Think of the html tags as content delineators, and style sheets as layout guidelines.
posted by veedubya at 12:55 AM on February 20, 2005

I wish they'd told me...

That although PHP projects typically produce HTML a good engine will consider HTML just another format alongside RSS, Atom, and PDF.

And I wish I was told that to do that means you need some templating engine. XSLT is well supported in many languages but pipelines to be easy to develop in. XSLT sucks for some string reformatting though, and when you want a simple loop it can mean writing recursive templates - ugh. Smarty is a good too, though I don't know much about it.

And to help the templating engine do it's thing means providing good sources, which means valid XML (bits of xhtml). Storing strings and cleaning them up with regexps leads to simple mistakes like <b> <i> </b> </i>, which is the same reason I don't like UBB code. I think the only way to ensure good XML in the database is to use htmltidy though I'd like to use something lighter.

And that a database abstraction layer is good but it needs to be more than passing the same string of SQL to different backends. There needs to be abstraction above SQL so that it can be translated to each database's style of SQL. I wrote one for my forum that abstracted out some differences between MySQL and Postgres, though I would have liked to use something like Prevayler had it been available for PHP.

I think getting Apache to pass everything to one PHP script, rather than littering lots of .php files over the webserver, is easier to manage. That way you can treat the URL just as another variable, .php is never in the URL, and the URL is just another variable. That one doesn't matter so much though it's cute.

That's all what's perfect and I haven't found one that does it all. If the engine can produce good HTML and it's got a clever presentation layer that's good enough for me :)
posted by holloway at 12:56 AM on February 20, 2005

Keep your PHP out of your HTML as much as is humanly possible.

Seriously, I can't overemphasize how useful it is to seperate content and presentation.
posted by mosch at 1:51 AM on February 20, 2005

There's excellent templating engines available for PHP that separate presentation logic from application logic. This not only makes it easier to modify underlying code (tweak performance, add features) but it also allows for aesthetic changes that would not damage the overall function of the site.

So, as others have mentioned, keep business and presentation code separate, use require() to import a number of files that would be used across all areas of the site (header/footer especially) and classes are wonderful for taking common tasks (like SQL calls etc.) and making them much easier to use and compartmentalize.
posted by purephase at 4:21 AM on February 20, 2005

If you have 2 ounces of discipline in your body, you can use inline PHP as your "templating engine". You can't find a more flexible PHP templating system than PHP itself. The issue is keeping business/contol logic out of the presentation/view section of your app.

When prototyping, here's what I do:

1. Start a file
2. Divide the page into 3 sections -- model, control, view -- using comments
3. As you code, keep all database hits inside functions in "model", all code that is not specifically rendering html inside "control", and all code that renders html in "view".

All code is on the same page, but no section should never depend on that fact. You should always ask yourself: "could I replace, say, the control section of my code with a room full of monkeys looking up my information in the Library of Congress and then inputting it into the server each time the page reloads?"

If the answer is "yes", you have developed a 3-tier PHP app. Congrats!
posted by 4easypayments at 9:05 AM on February 20, 2005

I prefer to use a templating engine. (Sorry, in-line coders.) The reason I prefer to use a templating engine in a situation where a neophyte could possibly, potentially be editing the HTML is that they always seem to booger the PHP somehow by getting cute, even when I force them to use Dreamweaver or something where I can block off areas that they can't edit. Since that's usually a business requirement, I just started using templates all the time and found it's much easier.

To me, a well-laid out PHP application has five types of files:
- .php files that have the page display logic in them
- .form.php files that process forms (usually named the same thing as a form category ... for instance, I'll have message_read.php, message_archive.php, message_send.php, etc. .... and message.form.php that will process all of the input from any of those different forms or display pages.)
- .plt.html pages - template HTML pages, usually stored in the /plt subdirectory
- .obj.php files - PHP objects. More on those in a sec.
- .inc.php files - PHP code libraries that are reused in multiple places. I tend to group them so as to reduce the number of include/requires I have to run for page. For instance, I'll group all of the functions that munge strings into munge.inc.php

I use objects to (and yes, I know geeks, I can use triggers for this, but I'm trying to write mostly database independent code and not all databases have triggers...) access and update single records. For instance, say I have a user object. There are two fields that would qualify as individual identifiers, and that I need to be able to look up people with -- the userid field, the legacyid (old ids used in a previous, but integrated system). I write an object that has all of the fields the user's row would have in the database, and write a lookup method with two different queries -- one for if I'm looking up by id, one if I'm looking up by legacyid.
In the code, I instantiate an object, $user, and then set $user->id ... and then to populate the rest of the object, simply call $user->lookup(); ... I can then change $user->level, for instance, and call $user->update() to put it back into the database.

That's my standard, it works for me, but what works is very individual to different people. Find something that works for you and use it. As long as it's consistent, it's good.
posted by SpecialK at 12:29 PM on February 20, 2005

As an example to look through, I always found the applications in the Horde Project some of the nicer PHP applications I've run across in terms of cleanliness and manageability. PHP lets you get lazy, but as long as you know what to look out for and have sufficient discipline you can end up producing a manageable product.

Disclaimer: I'm still listed as part of the Horde core team, but it's been five or six years since I've been involved, and even then I was only maintaining documentation and the odd patch originating from our production IMP installation at my place of work.
posted by mendel at 8:07 PM on February 20, 2005

smarty saves lives. or at least sanity. you're on the right track with the tips above.
posted by anildash at 2:08 AM on February 21, 2005

« Older What was Freddie Mercury thinking?   |   What's cool to do in St. Louis? Newer »
This thread is closed to new comments.