6 Signs of Adaptive PHP

 

1. Use an associative array for function arguments

How:
function foobar ($args)
{
	$arg['hehe'] = !empty($arg['hehe']) ? $arg['hehe'] : 'a default value';
	$arg['hoho'] = !empty($arg['hoho']) ? $arg['hehe'] : 'a default value';
}
$returned = foobar(array('hehe' => 'foo', 'hoho' => 'bar'));
Benefits:
  • If you change function arguments, you may not need to change how the function is called elsewhere in your scripts
  • All arguments are potentially optional, so no need to be strategic about the order of your arguments in your function calls or declarations
  • Easy to add/remove/modify arguments and default values without worrying about function calls

2. Check if classes and functions exist for plugin detection

How:
if(function_exists('foo'))
{
	$returned = foo($bar);
}
if(class_exists('foo'))
{
	$fooclass = new foo($bar);
}
Benefits:
  • Now you can check for plugins to add additional functionality on the fly
  • Allows for deprecation and future compatibility of functions

3. Use require_once() instead of include() or require()

How:
require_once('foobar.php');
Benefits:
  • Including a script more than once creates errors and conflicts.
  • Using require_once() will prevent duplicate includes.

4. Return associative arrays from functions

How:
function foo($bar)
{
	$returnval['next'] = $bar['current'] + 1;
	$returnval['previous'] = $bar['current'] - 1;
	return $returnval;
}
Benefits:
  • Adding/Changing return values to increase the functionality of a function no longer invalidates previous calls
  • Functions can provide much more information about a function call, making the function more valuable

5. Use the little-known __autoload() in PHP5

How:
function __autoload($class)
{
	require_once($class . '.php');
}

$foo = new bar; // bar.php will be loaded automatically if not yet
Benefits:
  • No need to load everything up front
  • Only the files that are needed will be loaded
  • Simplifies object-oriented plugin detection

6. Automatically detect file locations with dirname(_FILE_)

How:
$currentdir = dirname(_FILE_);
require_once($currentdir . '/plugins/foobar.php');
Benefits:
  • Allows files to be moved around on the server without problems
Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Add to favorites
  • Design Float
  • DZone
  • email
  • FriendFeed
  • PDF
  • Propeller
  • Reddit
  • RSS
  • StumbleUpon
  • Twitter

Related posts:

  1. PHP Arrays Unleashed
  2. Creating an Ellipsis in PHP
  3. Implementing paging using PHP and jQuery
  4. PHP Classes and Objects: What do they mean to you?
  5. Create URL Shortener For Twitter Using PHP


Written by Brenley Dueck

 

35 Responses to “6 Signs of Adaptive PHP”

  1. Brian Cray Says:

    February 27th, 2009 at 2:24 pm

    Thanks for allowing me to do this guest post! I’m humbled to be on this blog :)

  2. | Brian Cray's Blog Says:

    February 27th, 2009 at 2:33 pm

    [...] “6 Signs of Adaptive PHP” at Brenelz.com, a good friend of mine. [...]

  3. Shane Sponagle Says:

    February 27th, 2009 at 2:35 pm

    Great post. Some very good tips in here. Thanks

  4. Isaac Van Name Says:

    February 27th, 2009 at 2:42 pm

    I love it! You presented good tips on how to write scalable and adaptive code. I especially liked the bit about passing an associative array to a function to allow the function to scale and meet any additional needs… That should be a must!

  5. Jason Lengstorf Says:

    February 27th, 2009 at 4:25 pm

    This is a great article, Brian!

    I especially like points #1 and #4 — I pass and return arrays in nearly all of my functions. This is especially useful for separating business logic from formatting, and it eases the use of templates for layout.

    The __autoload() function is another one that sees heavy use in my code. It might be worth noting that you can set the __autoload() to pull from a set folder, as well, like so:

    function __autoload($class)
    {
    require_once “/inc/$class.php”;
    }

    This will allow you to put all of your classes in the “inc” folder, keeping your application organized, and using the slash in front of the path means that the include will always look at web root first, so no matter where you are in your file structure, the include will look at http://www.example.com/inc/ for your class.

    One quick note about point #3: if you’re following the PEAR coding standard, you shouldn’t actually use the parentheses in require_once.

    From the PEAR docs (http://pear.php.net/manual/en/standards.including.php):
    “Note: include_once and require_once are statements, not functions. Parentheses should not surround the subject filename.”

    So, rather than:
    require_once(‘foobar.php’);

    Use:
    require_once ‘foobar.php’;

    Examples in the PHP manual also use the parentheses-free syntax of include_once and require_once.

  6. Awesome Links of the Week: 2009-02-28 « Jon Bergan - A blog about Design, Development & Being Your Own Boss Says:

    February 27th, 2009 at 9:07 pm

    [...] Six Signs of Adaptive PHP – Some good advice in here and definitely worth the read if you’re a developer. [...]

  7. Brenley Dueck Says:

    February 28th, 2009 at 12:26 am

    I am just as happy to have you on here Brian. Thanks for the tips as well Jason.

  8. MrStrider Says:

    February 28th, 2009 at 3:17 am

    good post, well done Brian. Thanks for the tips

  9. Bari Says:

    February 28th, 2009 at 4:31 am

    Great post and great tips. Very useful for effective and efficient coding.

  10. Tim Johannessen Says:

    February 28th, 2009 at 4:32 am

    I also like the #1 tip – haven’t really thought about it like that before, however this will also force you to throw the arguments as an array when invoking the specific function, which to me seems a bit narly and looks kinda odd, can’t really decide if the “bad look” makes up for the benefits you gain from this approach.

  11. jon bennett Says:

    February 28th, 2009 at 9:37 am

    re #1, I follow CakePHP’s lead and have required params (as few as possible) as normal args, then an array of optional args. You then have a $_defaults array which you merge with the passed options.

    function foobar ($param, $param, $options)
    {
    $_defaults = array(‘this’=>’that’, ‘when’=>’now’);
    $options = array_merge($_defaults, $options);
    }

    cheers,

    jon

  12. Renkli Says:

    February 28th, 2009 at 3:02 pm

    actually I think #6 is not necessary

    why? because using relative directory structure is enough: “.” – identifies this dir, “..” upper directory, so include “../anything” etc..

    (6. Automatically detect file locations with dirname(_FILE_)
    1.$currentdir = dirname(_FILE_);
    2.require_once($currentdir . ‘/plugins/foobar.php’);
    Benefits:

    * Allows files to be moved around on the server without problems
    )

  13. Ryan Rampersad Says:

    March 1st, 2009 at 2:14 pm

    Many javascript libraries have their classes setup so that the first couple of arguments are required and then last argument is always a javascript object which is passed in to overwrite pre-developer-set defaults.

    You could do this in PHP with #1, just like CakePHP does.

  14. Steve Clay Says:

    March 2nd, 2009 at 12:49 pm

    In #1, do not rely on empty(). empty can return true for several intentional values, and will result in needless NOTICEs when the arg isn’t specified. You want:

    $args['pref'] = isset($args['pref'])
    ? $args['pref']
    : ‘default’;

    empty()’s rules are so complex that it’s a great way to introduce invisible bugs. Better to be explicit in your code using isset(), === and !==.

  15. me Says:

    March 3rd, 2009 at 2:45 am

    When possible return on object instead of an array

  16. Dave Says:

    March 5th, 2009 at 4:19 pm

    @Steve Clay: additional gotcha to be careful of with isset() is for array values where the key=>value pair can have a null value. Consider:

    $arr = array();
    $arr['param'] = null;
    if ( isset($arr['param']) ) {
    //do something
    }

    isset() will return false – even though the key does exist. If $arr['param'] is false, 0, ” (empty string), isset() will return true.

  17. david Says:

    March 5th, 2009 at 5:48 pm

    #4 : what is wrong with using list to identify the values from the returned array?

  18. thepearson Says:

    March 5th, 2009 at 7:15 pm

    #1 – You want to be careful when using arrays as “catch all” parameters in functions. While it does make for easy expansion, it obfuscates the interface from the client. Good post.

  19. Andrew Says:

    March 5th, 2009 at 9:44 pm

    Wow, this is like the really half-assed shoot-yourself-in-the-foot version of best practices. All of these are based on good ideas, but (with the exception of 3) none of them are _actually_ a good way to do it.

    Using key/value pairs without discipline is a good way to turn an interface into mush.

    Using autoload is dangerous and should never be undertaken without knowing what you’re doing — an example as simple as the one here should never be used.

    Likewise with introspection — it’s a great idea but if you try to do anything as simple as the exists() examples here you’re going to dig yourself some huge holes and create some very _interesting_ bugs.

  20. Pinderkent: "Adaptive PHP" techniques help ensure bugs, unmaintainability, and other problems. Says:

    March 5th, 2009 at 9:51 pm

    [...] bugs, unmaintainability, and other problems.Posted on Friday, March 06, 2009 at 2:34 AM. The recent 6 Signs of Adaptive PHP article gives some examples of different PHP coding techniques. Unfortunately, it only bothers to [...]

  21. Andrew Lim Says:

    March 6th, 2009 at 4:39 am

    For tip #6, I think it should be __FILE__ with 2 underscores prefixed and suffixed instead of _FILE_.

  22. remy Says:

    March 6th, 2009 at 6:27 am

    i would advise the author to read up on design patterns. a different approach to for example #1 passing an array as a parameter could be this: http://sourcemaking.com/refactoring/introduce-parameter-object

  23. Matías Says:

    March 6th, 2009 at 7:06 am

    Nice :)

  24. Matt Says:

    March 6th, 2009 at 8:52 am

    I couldn’t disagree more with your first point. It increases your ability to add arbitrary function arguments – which is of arguable benefit – at the cost of clarity in code. You should use whatever data structure is appropriate for the required arguments. If it’s an integer, use an integer. You don’t need to wrap it in an array.

    As for point 3, this is solved through a sane include strategy, such as bootstrapping, that better structures your code. If you find yourself getting errors because you include the same file more than once, that’s a code smell, and a sign you need to reconsider your organization.

  25. 網站製作學習誌 » [Web] 連結分享 Says:

    March 8th, 2009 at 3:28 am

    [...] 6 Signs of Adaptive PHP [...]

  26. Giorgio Sironi Says:

    March 8th, 2009 at 5:00 pm

    I guess #6 is “Allows files to be Included around on the server without problems” (however is __FILE__).
    The __FILE__ magic constant is a string containing the script filename and is substituted on compilation, so if you do an include a file that contains #6 code, the require_once will continue to work even if your client file is in another folder.

  27. Best of the Web: February - NETTUTS Says:

    March 10th, 2009 at 8:11 am

    [...] Visit Article [...]

  28. Shuja Shabandri Says:

    March 11th, 2009 at 1:21 am

    I think setting defaults can be done in a better way.

    $defaults = array(‘hehe’ => ‘default hehe’, ‘hoho’ => ‘default hoho’);

    $args = array_merge($defaults,$args);

    This avoids a long list of isset or empty checks for all params.

  29. Pete W Says:

    March 11th, 2009 at 1:31 am

    /*
    * Until we have 5.3
    */
    if ( !defined(‘__DIR__’) ) {
    define(‘__DIR__’, dirname(__FILE__));
    }

  30. Pete W Says:

    March 11th, 2009 at 1:37 am

    function foo ( array $args )
    {
    $vars = array(
    ‘apple’ => ‘default’,
    ‘banana’ => ‘values’,
    ‘orange’ => ”,
    );

    $merged = array_merge($vars, $args);
    extract(array_intersect_key($merged, $vars));
    unset($merged, $vars);
    //code rest of function …
    }

  31. Jack Timmons Says:

    March 11th, 2009 at 12:08 pm

    How can you overlook __get and __set, yet include __autoload? ;)

    If you’re talking about having adaptive PHP, you should really encourage your followers to define a storage array so they can dynamically store variables using __get and __set.

  32. Jack Timmons Says:

    March 11th, 2009 at 1:12 pm

    Most of the comments against the ideas are valid, and using __get and __set shouldn’t even be used except in controlled situations. I’m going on the premise that they are in said situation. All I use __get and __set for are autoloading column names from a database to help addons later.

  33. Pras Sarkar Says:

    March 11th, 2009 at 1:20 pm

    This is a good article of quick and practical tips, but there are some caveats to using them.

    1. Using an associative array is fine, but remember that functions are APIs. If you’re working on a project with others, you’ll want them to find out the arguments and datatypes for those arguments by looking at your function definition. You lose this clarity when you clump everything into an associative array. There are uses for this, just not everywhere.

    3. Definitely a good tip. A minor caveat is that require_once() is slower than require() since it needs an additional hash lookup to see if the file has been included before.

    4. Again, similar drawbacks to #1, since now any changes you make to the returning associative array has the potential to break code that’s relying on the returned variables.

    PHP is a great flexible language with a lot of power. But with that power comes responsibility to stick to best practices (and break them only in special circumstances).

  34. Kaloyan K. Tsvetkov Says:

    March 11th, 2009 at 4:16 pm

    Man, where did you learned all that stuff. It’s crap ;) You lost me on #1. First, don’t use empty() for array elements which might now be there — use isset() instead ! If you use empty() in E_ALL error reporting (as we all should do), you will get the penalty of a friendly warning that the array element is not set for you to check it. Second, this is too much overkill. Even the array_merge() is too much code for me ;) You can do everything a lot easier:

    $arg = $arg + array('hoho' => 'default value 1', 'hehe' => 'default value 2');

    You know that you can do union like this, right ? If not, read the PHP manual again:

    http://php.net/manual/en/language.operators.array.php

  35. Kevin Says:

    April 12th, 2009 at 2:06 am

    I thought these were some great tips to consider. I’ve found that using empty() can be a little tricky sometimes. What works for me is to trim() the value first then test for strlen(). The the value is NULL or is bool FALSE, then it will have a string length of zero. Even if the value is 0, then it will at least have a string length of 1 and you know you have something. You can do further test from there. I’m not php expert, but it clears up confusion for me.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
connect with me!