12 Things Mango Wishes He'd Known When He Was a PHP N00b.


  1. Never use Register Globals.  Ever.  And if you ever even THINK of using Register Globals, and we find out, Mango is going to send someone over to your house to kick your ass.  Are we clear?
    As much as we love working with PHP, Register Globals is something that should be filed under "Monumentally Bad Ideas".  And unfortunately, it's something that, at first glance, appears convenient.  If a user submits a form to a PHP script with Register Globals enabled, the script will create a variable for each form element.  However, keep in mind that this allows your end users to set any variable in your script that they like.  Here is a common mistake that we see:
    if ($logged_in) { secret_functions_allow(); }
    In a situation like this, the author has first run some code to see if the user is logged in or not.  If so, the script will have defined the $logged_in variable.  When the above line of code fires, it will provide the user with some functions only availble to authenticated users.  Innocent enough, yes?  However, to "hack" this, all that a malicious user would need to do is form a URL like http://www.example.com/?logged_in=1.  To turn off Register Globals, add php_flag register_globals off to .htaccess or register_globals = Off to php.ini.  Many administrators ban use of Register Globals entirely, so by developing without it, your script will be more portable.  This is a good thing.

  1. Turn notices on when developing code.
    Yes, we know they're annoying.  However, notices provide you with some valuable information you can use both to improve your script and improve your skills as a programmer.  One thing that notices will alert you to is undefined variables.  Continuing with the above example, the fictitous script assumes that the $logged_in variable will be defined if the user is logged in.  Proper programming practice would be a scenario more like $logged_in==1 if the user is logged in and $logged_in==0 if not.  If notices are turned on, PHP will alert you to this.  To turn notices on, add php_value display_errors on and php_value error_reporting 2147483647 to .htaccess or display_errors = On and error_reporting = E_ALL to php.ini.  You can also use ini_set('display_errors', 1); error_reporting(E_ALL); in your PHP script however this will not display parse errors such as a missing quote or bracket.

    Security note: you should turn display_errors off for a production server.  It's best to use it only when developing code.
  2. Don't rely on Magic Quotes.
    Magic Quotes is a feature of PHP before (but not including) version 6.  It was originally created to help prevent SQL Injection however new thinking is that programmers should write secure code (!) rather than rely on Magic Quotes.
  3. Do not use the path to your files in your script.
    There's nothing worse than having to move servers in a hurry, realizing that you now have a new path to your home directory, and having to change a hardcoded path in dozens of files.  Instead of hardcoding paths, use $_SERVER['DOCUMENT_ROOT'] to have your script discover your document root.  Or, use dirname(__FILE__) to find the directory that the script is located in.  (Note that this is literally dirname(__FILE__) - you don't replace __FILE__ with anything.) Or, use the getcwd function.
  4. Avoid having the same or even similar code in different parts of your script.
    You want to do this simply because it's more efficient.  It's faster to write code when you don't have to write the same code over and over, it's faster to modify code when you don't have to modify it in multiple places, and it's easier for other people to read the finished product when the code is short.  If you have to do the same thing more than once in your script, use functions or loops.  If you have to do the same thing in multiple scripts, use include files.
  5. Don't do for ($i = 0; $i < count($array); $i++) {
    Yes, this will run and will often produce the desired results.  However, the count function will run at every single iteration.  Instead, it's faster to do:
    for ($i=0, $count=count($array); $i < $count; $i++) {
  6. Come up with a naming scheme for functions, variables, and column names.
    Someone once told us that functions and variables should all be named with as much care as one names their first child.  We agree.  If your naming scheme is effective, one should be able to guess names by looking at other names.  The Mailparse Extension is a good example of effective naming schemes.  Additionally, take care when defining the order of parameters in a function.  One example of why this is a good idea is the strpos function and the str_replace function.  These functions have two strikes against them.  By looking at str_replace, I would assume strpos would be named str_pos.  Additionally, the parameters are in different orders: strpos requires the subject first and str_replace requires the subject last.

    For naming functions, we separate words with underscores.  The first word in the name is a word that defines the general group of functions that we're writing, (for ease of identifying what the function is for, and also for ease of sorting when writing documentation) and then use more words as necessary to describe the function.  Similar functions should have parameters in the same order, with parameters that have default values at the end.  For naming database column names, we often use the actual human readable phrase, converted to lower case, with underscores instead of spaces.  This occasionally makes for a slightly long column name, but the advantage is that we can later use str_replace and ucwords to display the name and not need to cross-reference a list of human-readable column names.
  7. Use UTF-8
    There's a great article about using UTF-8 with PHP and MySQL at developer.loftdigital.com.
  8. Use SELECT * only when necessary.
    This is a MySQL tip, however we include it here because a great deal of PHP students also wish to learn MySQL.  SELECT * is not inherently a bad thing to do, however it's often misused.  The only time that it should be used is when you need to select every single column in a table and you do not know in advance what columns the table will have. We see many people selecting all columns in the table but only actually using one or two.  In this case, it's better to do something such as SELECT `first_name`,`last_name`.  This makes for a longer query, however since the entire row is not loaded, your script uses less memory.

    Here's an example of where you DO want to use SELECT *.  Let's say you have a program that displays information about customers from a database.  However, you intend to write the program so that it may operate with any database structure.  Because in this case columns may be added or removed in the future, and the program is to display all the information we have about a particular customer, we have satisfied both of the requirements for using SELECT *.
  9. Make a wrapper for MySQL queries.
    This might not be necessary for quick scripts but it's something we like to do for large projects.  The simplest wrapper is as such:
    function mysql_mangos_query($query) { return mysql_query($query); }
    There are many advantages to this technique.  For example, one may want to use the mysql_error() function to see if the query returned an error, and if so, write the error to a log.  Or, if one is working on a large project with multiple tables, one might want to prefix the tables with something like projectname1_ so that multiple instances of the project may run with different data.  One example of this is the content management system Joomla.  All of Joomla's queries look like SELECT [columns] FROM #__content WHERE... Joomla removes #__ and replaces it with the appropriate table prefix.
  10. Learn how to use regular expressions.
    Regular expressions are by far the most powerful underused feature of PHP that we see.  Students often avoid using them because they look intimidating.  We agree, however they're easy to get to know in 15 or 20 minutes.  They're often a very simple and efficient solution to data manipulation problems.  If you're a programming student, one can easily impress friends (well, fellow programming students anyway) by being able to read and write complex regular expressions.
  11. Finally, know where to go for documentation.
    It's always a good idea to have documentation at your fingertips.  We certainly don't claim to know every PHP function there is to know (although that would be really cool).  To find documentation on any function, simply go to http://php.net/functionname.  If you don't know the name of the function you need, look up a similar function and see if the one you want is listed as a related function.  Often, you will also find examples and tips on usage.  These are very helpful.  For example, someone wanting to find out if a string is contained within a string might look up preg_match.  However, this operation does not actually require regular expressions, and as the manual will tell you, it is faster in this situation to use strpos instead.

Happy coding!
 
  1. June 29th, 2009 at 12:07 | #1

    Mango,

    Great tips, however I would expand upon #10. Wrappers make life much easier and make the life of someone who wants to code properly much happier.

    I use some very standard 'shortcode' wrappers:

    query($SQL) -- like yours in #10, as well as:
    query_single($SQL) -- returns the first row
    query_all($SQL) -- returns an array with all result rows
    query_return($SQL) -- returns mysql_insert_id() so you can easily get the id of the item you inserted.
    esc($string) -- shortcode for mysql_real_escape_string($string, $GLOBALS['db_handler'])
    he($string) -- htmlentities($string)
    ue($string) -- urlencode($string)

    I also use some simple systems for things like debug info and notices to users, but that's kinda past the point of this. 🙂
     

  2. June 29th, 2009 at 15:32 | #2

    Thanks for elaborating!  Everyone, take note 🙂
     

If you would like a reply to your comment, you must leave your email address! We receive dozens of questions every month from people who don't leave us with any way to contact them, so we have no choice but to ignore the question. We try to reply to as many questions as we can, if we know the email address of the person who asked the question. Thanks in advance for writing in :)

Allowed HTML: <b>, <i>, <em>, <strong>. All other < and > will be replaced with &lt; and &gt;.