share
Stack OverflowHow Is PHP Done the Right Way?
[+103] [11] Mackristo
[2009-03-29 07:08:47]
[ php ]
[ http://stackoverflow.com/questions/694246/how-is-php-done-the-right-way ] [DELETED]

I keep hearing about how often php results in lousy code and practices. Given these criticisms and popularity of the language, what are best practices (in general) to insure that these poor habits are avoided? Following frameworks? Does it matter?

[+162] [2009-03-29 08:22:08] cletus [ACCEPTED]

I'm going to answer this question from the perspective of what not to do more than what to do. This is because I think that at the end of the day its more important to stamp out bad practices than it is to encourage good ones (which can be highly subjective anyway). Bad practices are most often universally agreed upon however.

The other thing I'll add is that in some ways this answer won't help you as much as it could because part of doing anything the right way--particularly something as loosely typed and structured as PHP--comes from experience so any answer given may help guide you but it'll only take you so far.

The first thing I'll say about PHP is that the advantage of PHP is that it has a low barrier to entry and is highly flexible. The disadvantage of PHP is that it has a low barrier to entry and is highly flexible.

I've seen some terrible PHP code. That's because anyone can (and does) pick it up and start programming with it. This of course leads them to do things the easiest way they can, which is usually the first way they find that does what they want (which is human nature in general).

The biggest problems I've seen in PHP are:

  • Not sanitizing input to SQL queries creating vulnerabilities to SQL injection
  • Not sanitizing user input and cookie data creating XSS (cross site scripting) vulnerabilities;
  • Interspersing database queries with other code, which just creates a mess;
  • Including files based on user input (eg include "$inc.php");
  • Cutting and pasting code rather than using functional decomposition; and
  • Not reusing code at all.

The advantage of PHP being highly flexible is that if you do know what you're doing PHP can be great because it just doesn't get in your way. By this I mean that I am primarily a Java developer of some 10+ years experience and the trend in the last 5+ years has been to go for highly layered approach to solving any problem.

So if you want to add an extra field on your Web page you have to add it to:

  • Your JSP page;
  • Your model object;
  • Your validation;
  • Your business object;
  • Your DAO;
  • Your persistence object;
  • Your query; and
  • Your table.

So you have to add it to eight different places even in the best case scenario where you only have three layers (presentation, business, persistence). Some people insist on having more. This quote [1]:

One more layer of abstraction and this problem should go away...

cracked me up because it's so true: the trend has become to almost pile on extra layers as a knee-jerk response in response to any problem. Now this is all well-intentioned but as they say the road to hell is paved with good intentions. All these layers seem aimed at avoiding mistakes and increasing quality but more lines of code = more errors. Period. So at best you're robbing Peter to pay Paul.

Anyway, to bring this back to PHP: it doesn't suffer from this many-layered paranoia, which is a good thing... so long as you know what you're doing. So I'd never advocate that someone learn PHP as a first programming language--or even a first Web language--because you need a sound basis in the fundamentals or you're just inviting disaster.

Programmers that are methodical, defensive and organized can write excellent PHP code. Amateurs can write disastrously bad PHP code.

General

  • PHP is a templating language, not a general purpose or even an object oriented language [2]. Embrace it. Don't fight it;
  • Don't introduce frameworks just for the sake of them. This goes back to the fundamental principle that you shouldn't solve a problem until you have a problem. Developers these days I find are somewhat "framework trigger happy" ("I'm sick of writing if (s == null || s.equals("")), lets add Apache Commons Validator to the project!");
  • Always reuse code rather than cutting and pasting it unless the code is so trivial (say under 10 lines) or would require too much parametrization (say 5+ parameters) to effectively reuse;
  • Strive to minimize lines of code as best you can;
  • Don't try and do things the Java, C# or Ruby way in PHP. Do things the PHP way. Those other languages each have fundamentally different models;
  • Never, ever, ever use require_once or include_once. Some will no doubt disagree with this but I see those as being symptomatic of laziness and poor organization. They're also slower than require and include [3] and arguably anathema to caching [4];
  • Always use opcode caching. This is usually as simple as turning APC on in your php.ini;
  • Use output buffering (ie ob_start() [5], etc);
  • Set up common constants, database connections and so on in a file that you include at the top of every one of your scripts; and
  • Be consistent. I can't stress how important that is.

Web Best Practices

These aren't necessarily PHP specific but should be done in any Web project.

  • Treat all user input (including cookie data) as if it had the plague. Quarantine it, sanitize it and behave as if all of your users are out to get to you. PHP has an excellent and comprehensive array of filtering functions [6]. Use them;
  • Never rely on Javascript for input validation. It can be useful from a user experience point of view but every input should be tested on the server in addition to whatever is done on the client without exception;
  • GZip everything. With Apache you can use mod_deflate [7] or, as I prefer to do most of the time, do it from the PHP level, which can simply be done by putting ob_start("ob_gzhandler") at the top of your scripts;
  • Mirror your directory structure with your menu structure. If you have an Account menu with View Orders in it, if I can't find a script at /account/vieworders.php (from your document root) you'd better have a pretty darn good reason why not;
  • Always version static content [8]. There are multiple ways of doing this but this one is pretty good;
  • Always minify Javascript [9];
  • Combine all your CSS and Javascript files into one of each and version/minify as above (more here [10]). Note: this doesn't mean you can't develop them in multiple files. In fact I would encourage you to do this from an organisational point of view. Just combine them at runtime. I have a js.php script that combines, minifies, caches and serves my Javascript content, for example;
  • For Javascript, CSS and image files use far-future Expires headers and ETags either directly with PHP or with a Web Server module;
  • Never store sensitive information or information of any kind that you trust or rely upon in a cookie. A cookie is just a session identifier, that's it.
  • Abstract your security so you can do things in your code like "if (is_admin()) { ... }" rather than putting direct session checks in your code; and
  • In a shared hosting environment store nothing sensitive in the session. Other sites on the same box can read your session information if they're so inclined.

Database

That's about all I can think of off the top of my head.

Lastly it's worth reading 7 reasons I switched back to PHP after 2 years on Rails [12].

[1] http://stackoverflow.com/questions/469445/last-words-of-a-programmer/469454#469454
[2] http://michaelkimsal.com/blog/php-is-not-object-oriented/
[3] http://stackoverflow.com/questions/209728/php-opt-code-caching-zend-acceleration-and-includeonce-vs-requireonce/210726#210726
[4] http://sb2.info/php-opcode-caches-require_once-is-slow/
[5] http://au2.php.net/manual/en/function.ob-start.php
[6] http://au2.php.net/filter_var
[7] http://httpd.apache.org/docs/2.0/mod/mod_deflate.html
[8] http://stackoverflow.com/questions/118884/what-is-an-elegant-way-to-force-browsers-to-reload-cached-css-js-files/118886#118886
[9] http://stackoverflow.com/questions/507818/how-to-organize-minification-and-packaging-of-css-and-js-files-to-speed-up-websit
[10] http://stackoverflow.com/questions/490618/multiple-javascript-css-files-best-practices
[11] http://stackoverflow.com/questions/621884/database-development-mistakes-made-by-appdevelopers/621891#621891
[12] http://www.oreillynet.com/ruby/blog/2007/09/7_reasons_i_switched_back_to_p_1.html

Your two points "Use exactly one Javascript and one CSS file;" and "No matter how you develop your CSS and Javascript files..." should be perhaps merged. I'm interested in your argument against using include/require_once. Can you elaborate on that point? Thanks. - strager
(2) Also, by "versioning" do you mean revision control? If not, what is your view on using revision control on PHP? (Surely you would prefer it, though I think PHP is kinda weird when it comes to sticking it in some version control system...) - strager
@strager: The argument against those is that if a file can be included twice because of some include you are doing it wrong. - X-Istence
@X-Istence, Certainly not the case with C++, where include guards are common practice. I guess such reference issues don't occur much in PHP? - strager
(3) By "versioning" I mean the filename of your CSS/JS/image file changes when the underlying file changes. SO, for example, uses a query parameter for this (see the source). I tend to use the mtime of the resource. This allows you to use far futures expires header yet still change the resource. - cletus
@strager: It is generally considered bad practice in PHP since it is an interpreted language. include_once and require_once take more time since they have to keep track of the files that are included. In C++ this time is spent by the pre-processor, and waiting just a few seconds more is not an issue - X-Istence
X-Istence: no matter whether you call include or include_once the filename is still inserted into the list of included files. The only difference is the _once call checks the return code from insert which tells it whether the record was found or not. us3.php.net/manual/en/function.get-included-files.php - jmucchiello
(2) Is stackoverflow cutting off this answer? The comments seem to reference things that aren't showing up for me, but the edit history indicates that they should be there. - AgentConundrum
(2) PHP may be used largely as a templating language by new/casual developers, but that does not make it a "templating language"--at least no more than ASP/JSP/Python/Ruby/Perl/etc. - Lèse majesté
(2) @AgentConundrum @cletus: Can't believe nobody with enough rep came to fix this in the past 9 months. I seem to have managed to restore the entire answer now. - BoltClock
Before talking about other points, I fail to see how any of the below is inherently related to PHP itself? I'm no zealot of PHP but still don't think it should get everyone else's stick. "Not sanitizing input to SQL queries creating vulnerabilities to SQL injection Not sanitizing user input and cookie data creating XSS (cross site scripting) vulnerabilities; Interspersing database queries with other code, which just creates a mess; Including files based on user input (eg include "$inc.php"); Cutting and pasting code rather than using functional decomposition; and Not reusing code at all." - Halil Özgür
Totally wasn't worth reading those 7 reasons for switching back to PHP. Content of that post is irrelevant. "Rails is bad cause I love fiddling with raw SQL" - who cares (not mentioning comparison of PHP and Rails...)? - marines
"Never, ever, ever use require_once or include_once". Well, importing functions cannot be done twice, when importing dependencies in a PHP file. So you should remove that bold, and clarify what you mean. - Tiberiu-Ionuț Stan
1
[+12] [2009-03-29 07:34:12] CMS

I would suggest you to read and follow coding conventions from well known sources:

Whatever coding guidelines you choose to follow, the most important aspect is consistency.

I would also recommend you to use templating engines, to avoid making unmaintenable tag-soup files.

Give a look to Smarty [4].

[1] http://framework.zend.com/manual/en/coding-standard.coding-style.html
[2] http://pear.php.net/manual/en/standards.php
[3] https://trac.cakephp.org/wiki/Developement/CodingStandards
[4] http://www.smarty.net/

(28) Sorry, can't disagree more about Smarty. Still don't see the point of using a templating language for your templating language. - cletus
@cletus, Neither do I... I agree with trying to follow popular coding standards, though. Almost never A Bad Thing (tm), and it usually helps, especially when learning, to be guided by a rule book of sorts. - strager
2
[+4] [2009-03-29 07:20:11] X-Istence

Yes, it does matter. Those same programming practices are brought along to any new programming language that developer learns and the same mistakes are made all over again without knowing why they are wrong, and in other programming languages those mistakes can be costly, or cause maintenance nightmares.

PHP has a very low entry level, it does not require much to get your first web script up and running and in general is very forgiving. Users don't have to worry about handling variables correctly, there is no type checking, there is no real structure required.

There is also very little though built into the PHP programming language concerning security. Users are able to easily use variables that are given to them by users and place them inside their output. There is very little regard for type checking, and most users don't worry about passing by value or reference.

As to how to avoid such programming practices? I don't have a clear cut answer. Training and better tutorials out there on the web with more warnings and more clear guidelines would help. Checking out how the big guys do it and learning from them is considered good practice. Using frameworks that already exist force one to follow their guidelines, and to use their various pieces of infrastructure that exists, thereby making it harder to make "rookie" mistakes.

One last note, I don't think that PHP is the only offender out there, it just happens to be the worst offender because it is so ubiquitous out there, any user is able to buy hosting that offers PHP, there are even free hosts that offer PHP. It is also one of those programming language that since it can be embedded into HTML extremely easy there are many different tutorials and guides out there offering people simple ways to add a guest book to their web-site, or a counter, or an email form, etc...


(1) I agree with most of what you said. It is also notable that a lot of "put a guestbook on your site in PHP" recipe are of very low code quality anyway. Regarding security though, PHP 5 is much better in that regards (then several other web technologies), and PHP 6 will be better still. - Guss
@Guss: That is exactly why I used the guestbook one as an example, so many people believe they can do it and post examples and others pick those up :/. PHP 5 is better, but still not that great, PHP 6 is getting there but it will be a long time till the coding habits of the general populace change. - X-Istence
@Guss: To embrace the various new security features that are present in PHP 5/6, and most still demand register_globals to be turned on in PHP 5, when the default is to turn it off. - X-Istence
(2) The poor quality of available tutorial material is really one of the biggest problems with PHP. When even the official documentation is blithely concatenating unescaped strings into HTML, what chance does Joe Newbie have of avoiding XSS attacks? - bobince
3
[+4] [2009-03-29 07:20:47] Guss

Picking up PHP as a first programming language is a major issue as PHP doesn't really lend itself to learning good programming practices, and often results in poor code quality and a lot of unlearning that must be done before taking on another language.

That being said, I think PHP as a web development technology is a good choice - I'd just be careful who I teach it to. You can mitigate most of these concerns by doing things like:

  • Learning a good general programming language as a first language, such as C#.
  • Reading a good general programming book, just to get some understanding how good programmers write code, like Design Patterns.
  • Working with more experienced programmers on an existing project and making sure they do code review on your code - open source projects lets you get both for free.

Using a framework is not that good an idea (for picking up good skills), unless you pay a lot of attention to how the framework itself is written and you play with some framework code yourself. But please consider one of the above options as well.


Using frameworks usually requires understanding how the framework works, as in the API it has available. This means that the programmer is forced to work in a certain way to get to what he wants to get, thereby learning that doing things one way over another is better. It can go either way ... - X-Istence
Yes... and no. Frameworks do not teach you good programming skills like when to init your vars and when you don't need to, how to use boolean evaluations effectively, proper execution flows etc'. They only force an API on you which you may or may not understand. - Guss
4
[+2] [2009-03-29 07:22:06] carl
  1. The most important is not using register_globals. Complementary to that, make sure you always declare and initialize your variables before you use them.

    This is generally bad:

    <?php
    echo $foo;
    

    and this is generally good:

    <?php
    $foo = 0;
    echo $foo;
    
  2. Always remember to sanitize your queries when doing an SQL query. To aid you in cleaning your inputs to SQL queries, consider using PDO.

  3. Don't let the simplicity of the language think you can make poor design choices. Probably the main reason why C or C++ code is so much better is because programmers must critically think about every decision. In PHP, it is easy not to think at all, resulting in horrible code.


I agree with 2 and 3 but not with 1. register globals isn't inherently evil. In fact it can be quite convenient. - cletus
(2) @cletus: No, they are inherently evil because people don't understand what is going on, and variables are now randomly being declared that they don't expect to be declared in their code. In this code sample alone, with register_globals I can set $foo to what I want, and not let it be "" which is - X-Istence
(2) @cletus: probably what the author expected. It is never a good idea to let an outside "user" just set random variables within another persons program. This alone is the single biggest mistake that the PHP programmers ever made and luckily in PHP 6 it disappears entirely. - X-Istence
I fully understand the arguments against register globals, I just don't necessarily agree with them. I'd say SQL injection has been and is a far bigger problem so singling out register globals seems a tad arbitrary to me. In fact I've never even seen code where it could be a problem. Not so with SQL - cletus
(1) Consider the code: <?php while ($x < 10) { do_something($x); $x++; } ?> This code assumes that $x is implicitly set to 0. It may be imperative that do_something() run exactly 10 times, no more, and no less. An attacker could make $x a negative number and have do_something() called many times. - carl
Like I said, I understand the reasons but I have never seen code like that and I've seen some awful PHP code. - cletus
@cletus: There is also the whole include("$somevariable.php"); that many newbies used to create their first website based on index.php?view=about stuff. - X-Istence
The real flaw with register_globals is magic_quotes. If $id is set from $_GET are the extra slashes in it or not? The utility that register globals was supposed to provide is destroyed by magic_quotes. If you really like register_globals you can use extract to simulate it and you can call stripslashes (or addslashes) to make sure the variables extracted are in the format you want. - jmucchiello
5
[+2] [2009-03-29 17:46:03] wiseguy

I'd recommend programming with error_reporting(E_ALL); in each application, or effectively doing the same by modifying/inserting the following into the php.ini configuration file:

display_errors = On
error_reporting = E_ALL

This will display all applicable warnings and errors to you in respect to your code, which might normally be ignored. If you do not initialise a variable, say, PHP would not typically display a warning. With this configuration however, you will be notified.

This is not purely for bug-finding, this also helps enforce good programming practice. If you're getting warnings for problems such as uninitialised variables, you're doing it wrong and need to amend your practices.

Of course, don't enable these warnings on a production machine, just your development one. :)


I tried this a couple of times but E_NOTICE is so finnicky I just couldn't hack it so I go E_ALL ^ E_NOTICE as standard. - cletus
(2) E_NOTICE is not too finicky. Handling it's warnings is worthwhile. E_STRICT is too finicky. - jmucchiello
(1) I program with E_ALL | E_STRICT, would never do it any other way. Remember E_STRICT is going into E_ALL in PHP 6 - Ólafur Waage
6
[+2] [2012-08-15 19:57:56] thesmart

Adding closing "?>" tags to the end of php files can lead to accidentally pushing white-spaces to the output buffer. The PHP interpreter will automatically add closing tags to files, and doing it manually is somewhat of an anti-pattern.


7
[+1] [2010-01-08 00:55:57] 86Stang

Proper code structuring and commenting will make even garbage code readable to others and will make your life easier in the long run. Even if you're writing poo for code, so long as others can follow the structure and comments, you'll be ahead of the game.


8
[0] [2009-03-29 07:23:23] Roch

You should have a look to this article, there is a php section with quite a few framework you can use. I find php really hard to maintain if you don't follow a design pattern.

MVC [1]

[1] http://en.wikipedia.org/wiki/Model-view-controller

9
[0] [2009-03-30 12:49:45] dhperry

I find the biggest problem that I run into when trying to debug, edit or even understand PHP code is a lack of comments and documentation. This is the same problem that I find with HTML. This may be because web developers never got into the habit of commenting HTML. When is the last time you saw a comment in HTML source code? I asked one of my faculty members who teaches web development how much time is spent discussing comments. He said that the only coverage was a mention in the book.

I rarely find comments about functions, variable declaration, or anything else. It takes more time to find out what is being done than fixing the problem.

I would also echo other comments about learning good programming techniques. Again, this may be because many PHP programmers are web developers without programming experience. This is not meant to disparage the web developers. It is a different skill set.


10
[0] [2009-05-17 12:37:11] Jordie

I see a lot of code that does this:

include "$page.php";

where $page is a GET parameter, sometimes not even validated or sanitized. I am not a fan of this technique in the first place but don't if you must do it sanitize your data.


11