views:

693

answers:

10
+5  Q: 

PHP Idioms?

I'm looking to improve my PHP coding and am wondering what PHP-specific techniques other programmers use to improve productivity or workaround PHP limitations.

Some examples:

  1. Class naming convention to handle namespaces: Part1_Part2_ClassName maps to file Part1/Part2/ClassName.php

  2. if ( count($arrayName) ) // handles $arrayName being unset or empty

  3. Variable function names, e.g. $func = 'foo'; $func($bar); // calls foo($bar);

+5  A: 

My experience with PHP has taught me a few things. To name a few:

  • Always output errors. These are the first two lines of my typical project (in development mode):
ini_set('display_errors', '1');
error_reporting(E_ALL);
  • Never use automagic. Stuff like autoLoad may bite you in the future.

  • Always require dependent classes using require_once. That way you can be sure you'll have your dependencies straight.

  • Use if(isset($array[$key])) instead of if($array[$key]). The second will raise a warning if the key isn't defined.

  • When defining variables (even with for cycles) give them verbose names ($listIndex instead of $j)

  • Comment, comment, comment. If a particular snippet of code doesn't seem obvious, leave a comment. Later on you might need to review it and might not remember what it's purpose is.

Other than that, class, function and variable naming conventions are up to you and your team. Lately I've been using Zend Framework's naming conventions because they feel right to me.

Also, and when in development mode, I set an error handler that will output an error page at the slightest error (even warnings), giving me the full backtrace.

changelog
if( isset($array[$key]) ) will fail if $array[$key] is null. You should use array_key_exists($key, $array).
staticsan
It won't throw an error, not even with E_ALL. I'm sure about this ;)
changelog
Both of them have the same result without giving ANY error...
Jrgns
Yes, but isset() is easier to remember ;) I never remember what's the haystack, what's the needle, and the functions aren't very helpful, like array_key should be $array and then $key, not the other way around...
changelog
I'd say always use __autoload, otherwise large project will end up including almost all files all the time. Additionally, it enforces sane file naming and directory structure.
porneL
I've read require_once is much more expensive than require ... maybe something to remember on projects where performance is important.
alex
Not a huge difference if you do things right. Passing the full path to require_once will make it no different from require except from the fact that it will check if the file was required before.
changelog
+4  A: 

Fortunately, namespaces are in 5.3 and 6. I would highly recommend against using the Path_To_ClassName idiom. It makes messy code, and you can never change your library structure... ever.

The SPL's autoload is great. If you're organized, it can save you the typical 20-line block of includes and requires at the top of every file. You can also change things around in your code library, and as long as PHP can include from those directories, nothing breaks.

Make liberal use of === over ==. For instance:

if (array_search('needle',$array) == false) {
  // it's not there, i think...
}

will give a false negative if 'needle' is at key zero. Instead:

if (array_search('needle',$array) === false) {
  // it's not there!
}

will always be accurate.

Lucas Oman
Unfortunately, the namespace separator will be backslash. Really, I'm not joking!
Tom
TBH, I don't think '\' is that terrible of a separator.
Lucas Oman
+5  A: 

See this question: Hidden Features of PHP. It has a lot of really useful PHP tips, the best of which have bubbled up to the top of the list.

nickf
+2  A: 

I've been developing with PHP (and MySQL) for the last 5 years. Most recently I started using a framework (Zend) with a solid javascript library (Dojo) and it's changed the way I work forever (in a good way, I think).

The thing that made me think of this was your first bullet: Zend framework does exactly this as it's standard way of accessing 'controllers' and 'actions'.

In terms of encapsulating and abstracting issues with different databases, Zend_Db this very well. Dojo does an excellent job of ironing out javascript inconsistencies between different browsers.

Overall, it's worth getting into good OOP techniques and using (and READING ABOUT!) frameworks has been a very hands-on way of getting to understand OOP issues.

For some standalone tools worth using, see also:

Smarty (template engine) ADODB (database access abstraction)

philistyne
+2  A: 

There are a few things I do in PHP that tend to be PHP-specific.

  1. Assemble strings with an array.

    A lot of string manipulation is expensive in PHP, so I tend to write algorithms that reduce the discrete number of string manipulations I do. The classic example is building a string with a loop. Start with an array(), instead, and do array concatenation in the loop. Then implode() it at the end. (This also neatly solves the trailing-comma problem.)

  2. Array constants are nifty for implementing named parameters to functions.

staticsan
Explain no.2 or give some example code, please?
Jrgns
Like this: echo InputForm(FORM_TEXT, 'name', $name, array('width'=>40, 'required'=>true)); The fourth parameter has a number of different parameters depending the type of the first parameter.
staticsan
+7  A: 

Ultimately, you'll get the most out of PHP first by learning generally good programming practices, befure focusing on anything PHP-specific. Having said that...


Apply liberally for fun and profit:

  1. Iterators in foreach loops. There's almost never a wrong time.

  2. Design around class autoloading. Use spl_autoload_register(), not __autoload(). For bonus points, have it scan a directory tree recursively, then feel free to reorganize your classes into a more logical directory structure.

  3. Typehint everywhere. Use assertions for scalars.

    function f(SomeClass $x, array $y, $z) { assert(is_bool($z)) }

  4. Output something other than HTML.

    header('Content-type: text/xml'); // or text/css, application/pdf, or...

  5. Learn to use exceptions. Write an error handler that converts errors into exceptions.

  6. Replace your define() global constants with class constants.

  7. Replace your Unix timestamps with a proper Date class.

  8. In long functions, unset() variables when you're done with them.


Use with guilty pleasure:

  1. Loop over an object's data members like an array. Feel guilty that they aren't declared private. This isn't some heathen language like Python or Lisp.

  2. Use output buffers for assembling long strings.

    ob_start(); echo "whatever\n"; debug_print_backtrace(); $s = ob_get_clean();


Avoid unless absolutely necessary, and probably not even then, unless you really hate maintenance programmers, and yourself:

  1. Magic methods (__get, __set, __call)

  2. extract()

  3. Structured arrays -- use an object

Preston
Why use spl_autoload_register above __autoload?
Jrgns
spl_autoload_register() allows multiple autoload functions to exist. Useful for combining code from multiple sources.
Preston
porneL
+2  A: 

Declare variables before using them!

Kevin
+1  A: 
  1. Enable NOTICE, and if you realy want to STRICT error reporting. It prevents a lot of errors and code smell: ini_set('display_errors', 1); error_reporting(E_ALL && $_STRICT);
  2. Stay away from global variables
  3. Keep as many functions as possible short. It reads easier, and is easy to maintain. Some people say that you should be able to see the whole function on your screen, or, at least, that the beginning and end curly brackets of loops and structures in the function should both be on your screen
  4. Don't trust user input!
Jrgns
A: 

Thanks all for your answers. There is a some very helpful stuff here.

I have a slight issue with the point about namespaces (and not using the Path_To_ClassName approach) because the feature has taken a long time to arrive IMO and 5.3 alpha1 isn't production ready yet. So the rest of us have been making do with whatever works in the meantime. Better late than never, though.

Clearly, there isn't any one right answer to this question, but I'm going to vote up all the answers so far (assuming the site lets me).

Andrew Whitehouse
A: 

Get to know the different types and the === operator, it's essential for some functions like strpos() and you'll start to use return false yourself.

too much php