Twice a month, we revisit some of our readers’ favorite posts from through out the history of Nettuts+. This tutorial was first published in January, 2011.
There's an old adage - dating back to the 1700s - which, in English, says: "A kitten dies each time a PHP programmer doesn't follow best practices." Okay, not really; but just go with it!
Getting started in PHP can be a daunting experience. With that in mind, these 20 tips will teach you how to follow best practices, and save lives...kitty lives.
0. Program as Often as You Possibly Can
Programming often and with purpose will make the lessons you learn stick.
Did you study a foreign language in school? Studied all the parts of speech, learned the verbs and how to conjugate them, followed along as your teacher said common phrases?
How much of that language do you still speak?
If you're answer is, "none," I'm willing to bet it's due to the fact that you never actually used the language — you only studied it. But if you can still hold up a conversation, it's likely because you actually spent some time speaking that language outside of the learning environment. Perhaps you spent a year abroad, or worked a job where a second language was necessary?
Whatever the reason, you retained it because you used it in real-life situations and put it into a personal context that is much easier to recall later.
PHP is a foreign language, just like Spanish or French. In order to become comfortable with it, you need to use it outside of the classroom setting. Tutorials and sample projects are great for teaching the fundamentals, but unless you're applying those concepts to your own projects, it will be much more difficult to apply those fundamentals in context and burn them into your memory.
So, don't worry that you "don't know enough" to build a project. When you choose your project, you have a valid reason to research and implement a concept. Programming often and with purpose will make the lessons you learn stick.
1. Get Familiar with the PHP Manual
Every list of tips for beginners has this tip, and for good reason.
Learning to navigate the PHP documentation is the single most useful thing you can do for yourself as a programmer.
If you look in my browser history at the sites I most often visit, the PHP manual will be right at the top. I don't suspect that will change for as long as PHP remains my programming language of choice.
At first, the manual does look rather daunting — it doesn't seem to be particularly easy to browse, and the navigation can be a bit awkward at times. However, you'll get the hang of it quickly.
Perhaps the best thing to know about the PHP manual is that most functions can be looked up using the pattern http://php.net/function-name
in your address bar. For example, to look up the strpos()
function, use http://php.net/strpos, and for array_key_exists()
, use http://php.net/array-key-exists. (NOTE: pay attention to the omission of parentheses and the substitution of hyphens (-
) for the underscore (_
) in the address.)
1a. Read the Comments!
It's easy to overlook the comments, but do yourself a favor and have a look through them. If you're getting an unexpected result from a function, chances are someone has spotted it and explained it in the comments.
You can also pick up a plethora of great tips and ideas from the developer community by reading through comments.
2. Take Advantage of the Huge Online PHP Community
In addition to the PHP manual, there are wonderful developer communities all over the internet. Some of my personal favorites include StackOverflow.com and the W3Schools.com forum.
Additionally, Twitter is a surprisingly excellent place to post PHP questions. If you tag a tweet with #PHP, it's likely someone in the community will spot it and lend a hand.
A Note About Twitter: Of course, anything that's useful will inevitably be overrun with spammers and those sorry individuals who deeply misunderstood the purpose of social media. If you're going to use Twitter as a support network, you'll probably want to routinely block or hide the accounts which spew job postings or retweet everything that mentions PHP.
Just remember: as you get better, please try to pay it forward. The development community needs everyone to pitch in, and it won't be long before you'll have the ability to answer questions for other beginners. Don't turn a deaf ear.
3. Don't Put Off Best Practices for Later
As you're learning, you're going to hear a lot about "best practices" in programming; stuff like prepared statements and PEAR coding standards.
Do not put off learning this stuff because it seems hard.
If something is a best practice, it's not because we (meaning other PHP developers) got together and said, "How can we make life harder for the noobs?"
Best practices exist to keep your scripts secure, fast, and manageable. Learn them as early as you can. In fact, don't even bother learning the wrong way.
It takes just about the exact same amount of learning to figure out mysql_query()
as it does to learn PDO or MySQLi. So if you start with your choice of the latter two, you're starting with a strong foundation in database interaction and, really, you've put in less overall effort.
Be sure to browse Nettuts+ for a variety of tutorials on PHP best practices, including prepared statement usage.
4. Don't Put Off Best Practices for Later!
I just wanted to make sure you saw this.
Seriously, folks. Don't take shortcuts. Every time you violate best practices because the right way seems "too hard," BP dips a kitten in crude oil.
So if you won't do it for yourself, your projects, your peers, or the advancement of the community at large, at least consider the kittens.
5. Make Code Self-Documenting
If you need to squeeze characters off your variable names to shave .2ms off your script’s execution time, there’s likely a whole different problem going on.
It's tempting, early on, to be "clever" with your variable and function names. Maybe you read an article about performance, or saw a code snippet that accomplished a ton of work in two lines of code. Maybe you want to create your own "signature style" of coding. Maybe you just heard that I hate it and you wanted to piss me off.
Whatever your temptation, resist it at all costs.
Consider the following snippet of code:
<?php $a = b('[email protected]'); $c = explode('@', $a); $d = $c[1]; echo 'The email address ', $a, ' belongs to the domain ', $d, '.'; function b($e) { return htmlentities($e, ENT_QUOTES); } ?>
Does that make any sense to you?
Of course, you can figure out what it does, but why force anyone trying to work in your code to spend the extra 1-5 minutes scratching his head, trying to remember what $c is storing.
So let's take that code and make it self-documenting:
<?php $email = sanitize_string('[email protected]'); $email_pieces = explode('@', $email); $domain = $email_pieces[1]; echo 'The email address ', $email, ' belongs to the domain ', $domain, '.'; function sanitize_string($string) { return htmlentities($string, ENT_QUOTES); } ?>
There. Much better. Now, just by glancing at the code, you can get the general idea of what's going on. No head-scratching, no muttered curses, and most importantly, no real difference.
Sure, you save a few bytes with short variable names. But, honestly, if you need to squeeze characters off your variable names to shave .2ms off your script's execution time, there's likely a whole different problem going on.
6. Add a Comment to Anything You Had to Think About
Comments are the sign of a competent programmer.
Comments are not the sign of a novice. In fact, as I see more and more code that's not mine, I'm starting to think that comments are the sign of a competent programmer, as they seem to be the only ones doing it.
If your code is self-documenting, you won't require too many comments. However, no matter how clear your variable and function names are, you'll always have spots where the action taken simply isn't that obvious.
When that happens, slap a comment in there. "Future You" will give "Present You" a high five when the time comes to update the script.
As a rule of thumb, if you had to stop and think for a few seconds about what needed to happen to make the script work properly, it's probably a good spot for a quick note.
Consider the following:
$pieces = explode('.', $image_name); $extension = array_pop($pieces);
What does that do? Did you have to stop and think about it? Do you still not know for sure what's stored in $extension?
Look at that snippet again, but with one quick comment:
// Get the extension off the image filename $pieces = explode('.', $image_name); $extension = array_pop($pieces);
Now, even if you don't know how or why that code works, you at least know that $extension
refers specifically to an image extension. If that saves "Future You" or another developer five seconds of processing the script's intent, it was well worth your ten seconds of effort to add the comment in the first place.
As with most things, moderation is key. Too few comments and you risk leaving the next developer (or Future You) puzzled by a code snippet, which can even lead to accidental breaking of code because the solution, without explanation, might look silly or superfluous. Too many and it becomes too difficult to scan through your code, which is equally frustrating.
Moderation is key.
7. Learn Docblock and Use It
If I could be sure every developer in the world would do one thing with absolute consistency, I think it would be the use of the Docblock commenting standard.
I have a few reasons for my strong support of Docblock:
- It requires one to think about the what and why for each file, function, method, and so on.
- It gives a clear description of the expected types for parameters and return values in functions/methods
- It provides a quick description of what the code does
- When coupled with one of the many IDEs that support Docblock, it creates code hinting (which allows you to see a description and expected parameters/return values for the method or function you're using)
This tip does border on the upper level of beginner, but I group this under "best practices to be learned as quickly as possible." Feel free to skip it, but before you do, think about the kittens.
Docblock shows its versatility best when used to document a class:
/** * A simple class to get the sum or difference of $_foo and a value * * @author Jason Lengstorf <[email protected]> * @copyright 2011 Copter Labs * @license http://www.opensource.org/licenses/mit-license.html */ class CopterLabs_Test { /** * The value to use in addition and subtraction * @var int */ private $_foo = 0; /** * Adds a value to $_foo and returns the sum * * @param int $add_me The value to add to $_foo * @return int The sum of $_foo and $add_me */ public function add_to_foo( $add_me=0 ) { return $this->_foo += $add_me; } /** * Subtracts a value from $_foo and returns the difference * @param int $subtract_me The value to subtract from $_foo * @return int The difference of $_foo and $subtract_me */ public function subtract_from_foo( $subtract_me=0 ) { return $this->_foo -= $subtract_me; } }
At first it might look overwhelming, but the benefits are very much worth taking the time to familiarize yourself with the syntax.
The above Docblock, when used in Netbeans, will generate the following code hint:
8. Don't Be Too Hardcore to Use an IDE
If you don't already know the type, you will soon: the developers who think real programmers don't use IDEs.
Now, look: if you want to impress people, learn to juggle. Refusing to use anything but Emacs in the command line to write scripts will not get you chicks or grant you instant hacker status; it will, however, hang a sign on your forehead warning your coworkers that you are, in fact, That Guy.
Don't be That Guy.
There is nothing wrong with using software to give you on-the-fly syntax highlighting, error-checking, and code hints.
How in-depth your IDE goes is entirely up to you. Personally, I really like Netbeans. I've heard tons of praise for Coda for Mac (though it's not really an IDE), and I previously used Eclipse before moving to Netbeans.
Whatever IDE you choose, you'll see your coding speed increase and your facepalm-worthy bugs decrease. Further, as you expand your code library, you'll have code hinting for all of your custom software. (Because you're using Docblock, right? Right?!)
Don't think IDEs are uncool -- no matter what "That Guy" tries to tell you.
9. Group Common Code Into Functions
If you see an action repeated, it's time to strongly consider moving that code into a function.
When you first start programming, it's easy to start at the top of the page and work down, adding each piece of code right where it's needed.
However, when you code this way, you'll begin to notice that certain pieces of code are appearing over and over again. This is a minefield when it comes to maintenance and upgrades, because you have to hunt through each file for every occurrence of that action to change its functionality.
If you see an action repeated, even if it's only twice, it's time to strongly consider moving that code into a function.
Consider the following for example:
$unclean1 = '<a href="javascript:alert(\'Holy Crap!\');">Click Me!</a>'; $detagged1 = strip_tags($unclean1); $deslashed1 = stripslashes($detagged1); $clean1 = htmlentities($deslashed1, ENT_QUOTES, 'UTF-8'); $unclean2 = "Let's call Björn!"; $detagged2 = strip_tags($unclean2); $deslashed2 = stripslashes($detagged2); $clean2 = htmlentities($deslashed2, ENT_QUOTES, 'UTF-8'); echo $clean1, "<br />", $clean2;
As you can see, both of those strings required a few steps before they could be considered safe to use. However, you'll also notice that those same steps could be considered necessary for every bit of information that is passed to the script.
This is an instance where using a function instead is far more desirable:
$unclean1 = '<a href="javascript:alert(\'Holy Crap!\');">Click Me!</a>'; $unclean2 = "Let's call Björn!"; $clean1 = sanitize_input($unclean1); $clean2 = sanitize_input($unclean2); echo $clean1, "<br />", $clean2; function sanitize_input( $input ) { $detagged = strip_tags($input); $deslashed = stripslashes($detagged); return htmlentities($deslashed, ENT_QUOTES, 'UTF-8'); }
By wrapping the common code in a function, it's a bit easier to see what's going on, and it's much easier to edit the steps you want to take when sanitizing your input.
10. Group Related Functions Into Classes
Getting a handle on OOP is another one of those things that I file under "best practices to learn as quickly as possible."
If you have a handful of functions that all deal with database actions, you can save yourself a lot of time and effort by grouping them into classes.
Learning object-oriented programming is definitely outside the scope of this list, but I felt it was definitely worth mentioning in this beginners' list.
11. Use Constants, Not Globals
PHP allows you to define your own constants with the function
define().
When I first started programming on larger projects, I found myself using global variables more often than seemed necessary or reasonable. Admitting you have a problem is the first step.
I was storing things like application-wide data (such as the site's name or the maximum image width) and database credentials in variables, and I found myself required to use the $GLOBALS
superglobal to access this information.
Then I realized PHP allows you to define your own constants with the function define()
.
A constant is a great way to store information like the aforementioned app-wide data and database info. An additional bonus is that it can't be modified, so you can't accidentally overwrite your database password somewhere later in the script.
As a matter of best practices, the use of globals is generally discouraged to begin with, so the use of constants is preferred anyways. Review the following code for an example and see for yourself:
<?php define('FOO', 'constant value'); $bar = 'global value'; echo baz(); function baz() { $constant = ' Constant: ' . FOO; $global = 'Global: ' . $GLOBALS['bar']; return $constant . "<br />\n" . $global; } ?>
12. Don't Be Afraid to Use Includes
Often, as you're building larger products, it will make a lot of sense to break it apart into smaller chunks, or include files.
A generally accepted way to look at includes is to put any bit of code that will be used in multiple scripts into an include file (such as your database connection details, the header and footer data that is common across the whole site, utility functions like your input sanitization actions, etc.) so it can be pulled in by the file that needs it, rather than being copy-pasted.
For example, on a site with multiple pages, a standard template may emerge that looks something like this:
<?php // Application-wide data and database connection require_once 'constants.inc.php'; require_once 'database.inc.php'; // Utility functions require_once 'utilities.inc.php'; // Header markup require_once 'header.inc.php'; /* * Page-specific processing goes here */ // Footer markup require_once 'footer.inc.php'; ?>
13. Don't Obsess Over Performance
This is a point of near-paralysis for some developers, and it's really too bad; there is a blurry line between writing efficient code and wasting time trying to squeeze an extra 5ms out of a script's execution.
Definitely read a few performance articles and learn some of the major pitfalls that can drag your scripts to a slow crawl, but don't waste extra time refactoring your code to change double quotes to single quotes because you found out it was a tiny fraction faster.
Use your head, avoid the big problems, and keep your ears open, in case a tip you've never heard comes along to speed up your code, but don't make it a race.
No one can tell the difference between a 25ms page load and a 40ms page load. Make sure it's not 700ms and move on to more important things.
14. Avoid Marrying HTML to Your Scripts
This can be tricky, but do your best to avoid tangling up your HTML markup in your PHP. It's nearly impossible to get away from it completely, but try to make sure that you don't include any non-essential HTML markup in your code.
Consider the following:
echo '<div class="example-div"><p>This is some test content.</p></div>';
Was it necessary for that code to wrap the paragraph tag in a div? Could it have been modified to only include the paragraph tag that holds the text? Have a look at an alternative solution:
<div class="example-div"> <?php echo '<p>This is some test content.</p>'; ?> </div>
Note: This example is grossly oversimplified. Generating HTML with PHP is usually more of an issue when dealing with a complex function or method that organizes a dataset. The point I'm trying to make is that it can sometimes be tempting to include more markup than is necessary in the output.
In most cases you can keep the HTML outside the PHP, which makes things easier to read and, usually, easier to work with as well.
15. Try to Use at Least One Unfamiliar Concept in Every Project
Push yourself outside your comfort zone.
You're never going to learn if you keep doing the same old thing. Try out a concept that you're not quite comfortable with on every project you possibly can.
Don't be over-ambitious, but definitely push yourself outside your comfort zone. It gives you a challenge, saves you from getting bored doing the same old thing over and over again, and forces you to progress as a developer.
Look at the project, find all the bits that you know well (or at least well enough), and then pick an area you'd like to understand. Sign up for it. Then do it.
16. Don't Be Too Proud to Change
You will be wrong. Frequently. But that's not a bad thing.
As you improve, you'll find newer, better solutions to problems that you've faced in the past. Don't feel stupid; you're learning.
But it's extremely important that you don't become attached to the code you write. Don't think your way is better just because it's your way. If you happen across a great solution that makes yours look like a Band-Aid on a bullet wound, use it! Pay attention to what's different and what you did that could have been better. File that away under, "Things I've Learned."
Never allow yourself to believe that an inelegant solution is acceptable because it's yours. That's hubris (which, if you're not aware, doesn't generally result in happy fun times).
17. Validate
If you're a web programmer, start becoming familiar with input validation as soon as possible.
Keep in mind: validation is quite different from sanitization.
Input validation is the practice of making sure data matches the format you've requested, like checking an email field for a valid email address or ensuring that a submitted username is 8-20 alphanumeric characters.
It can be tedious and a pain in the ass, but making sure that only valid data makes it through your processing scripts will enhance the user experience and avoid a lot of bugs in the scripts that have to use the data later on.
18. Whitelists Instead of Blacklists
If you're not on top of your blacklist, vulnerabilities appear.
In plenty of situations, you'll want to block or get rid of certain tags, words, email addresses, or other various bits of data.
A common solution is to use a blacklist
: a collection of the tags, terms, etc. that aren't allowed.
This poses a problem, however; you have to be more clever than the person trying to do something naughty. For instance, in the case of disabling JavaScript in posts, you might blacklist the onclick
attribute, as well as most of the event attributes, but what if you forget one? What if a new one is added to the spec sometime in the future?
If you're not on top of your blacklist, vulnerabilities appear.
However, to save headache later, use a whitelist
whenever possible. A whitelist is the opposite of a blacklist: a collection of allowed tags, terms, etc.
For instance, in the strip_tags()
function, you can provide a whitelist to specify which tags are allowed in strings:
strip_tags($string, '<em><strong><tt>');
Now your problem is most likely going to be that you can actually do less than you wanted, but that's far safer and usually less of an emergency to handle.
You can't get away with it in every situation, but saying what is allowed vs. what isn't will provide you with more confidence and control over your scripts.
19. Learn to Count Like a Computer
Are you looking for tip #20? Remember that in nearly all cases, counts in PHP start at 0, so this is actually the 20th tip. You'll find this to be the case in most languages; don't let this one trip you up!
Summary
If you're a beginner, the tips covered above will help you take great strides toward good habits and best practices. Don't get overwhelmed if all of this is news to you; take things one step at a time (see tip #15).
Comments