PHP Functions, you’re doing it wrong…

Just a quick tip today. If your function looks something like this:

 
<?php
/**
 * A really long function definition
 * @param string $has
 * @param bool $a
 * @param int $lot
 * @param float $of
 * @param assoc_array $parameters
 * @param string $I
 * @param string $wonder
 * @param int $what
 * @param int $they
 * @param int $do 
 */
function myfunction(
	$has=null,
	$a=null,
	$lot=null,
	$of=null,
	$parameters=null,
	$I=null,
	$wonder=null,
	$what=null, 
	$they=null,
	$do=null
	){
	//do some magic
}
 
//this is how it would be called
myfunction(null, false, null, 1.2, array('one'=>1, 'two'=>2), 'I', null, 1, null, 3);

You are doing it wrong, if all of these parameters are really nullable and required for your function, and there is no way for you to split it up, then you _can_ refactor it like this:

 
<?php
/**
 * Quickly refactored to make it easier to use
 * @param array $array containing: (string)'has', (bool)'a', (int)'lot', (float)'of', (assoc_array)'parameters', (string)'I', (string)'wonder', (int)'what', (int)'they', (int)'do'
 */
function myFunction(array $array){
	//make sure we are only taking in parameters that we recognize...
	$has = isset($array['has'])? $array['has']:null;
	//array key exists because it is a fake boolean value... it has 3 possibilities
	$a = array_key_exists('a', $array)? $array['a']:null;
	$lot = isset($array['lot'])? $array['lot']:null;
	$of = isset($array['of'])? $array['of']:null;
	$parameters = isset($array['parameters'])? $array['parameters']:null;
	$I = isset($array['I'])? $array['I']:null;
	$wonder = isset($array['wonder'])? $array['hwonders']:null;
	$what = isset($array['what'])? $array['what']:null;
	$they = isset($array['they'])? $array['they']:null;
	$do = isset($array['do'])? $array['do']:null;
 
	//some magic
}
 
//it could also be written:
 
/**
 * Quickly refactored to make it easier to use
 * @param array $array containing: (string)'has', (bool)'a', (int)'lot', (float)'of', (assoc_array)'parameters', (string)'I', (string)'wonder', (int)'what', (int)'they', (int)'do'
 */
function myFunction(array $array){
	//make sure we are only taking in parameters that we recognize...
	$args = array('has', 'a', 'lot', 'of', 'parameters', 'I', 'wonder', 'what', 'they', 'do');
	foreach($args as $arg){
		$$arg = array_key_exists($arg, $array)? $array[$arg]:null;
	}
	//some magic
}
 
 
 
//this is how it would be called
//equivalent to:
//myfunction(null, false, null, 1.2, array('one'=>1, 'two'=>2), 'I', null, 1, null, 3);
myfunction(array('a'=> false, 'lot'=>1.2, 'parameters'=>array('one'=>1, 'two'=>2), 'I'=>'I', 'what'=>1, 'do'=>3));

It may be more to type, but it is harder to get it wrong when you are using named parameters. You don’t have to remember what each of the parameters do in their specific positions either so it is easier to understand the code as you quickly glance at it. Note that this is similar to the way that a lot of ruby functions are written, except we don’t have a short hand for named parameters like they do (it would be awesome if we did…):

 
myfunction(:a => false, :lot => 1.2, :parameters => { :one => 1, :two => 2 }, :I => 'I', :what => 1, :do => 3)

While this is definitely easier to read and remember, it is probably worth refactoring a function like this (as it is an extreme case) further because it is likely that you are doing way too many things within it.


Related posts:

  1. Documenting PHP Code
  2. RE: Top 10 PHP Techniques That Will Save You Time and Effort
  3. PHP Pop Quiz Hotshot
  4. Dynamic Images with PHP
  5. On naming functions sanely

Tags: , , , , , , , , , , , ,

  • http://tyrael.hu Tyrael
    • http://blog.seanja.com/ SeanJA

      Neat!

    • http://blog.seanja.com/ SeanJA

      Though… from reading that it is not really clear which way it is going, it seems mostly positive, but then there are the “I don’t know why we would ever need this” people who keep chiming in.

  • Wayne

    I am also concerned about the speed of this function, and also the memory that will be used to make the call.

    • http://blog.seanja.com/ SeanJA

      It really depends what you are doing, but for the most part it probably won’t matter too much in the grand scheme of things. That is, unless this is a heavily trafficked function. You actually don’t need to worry about the memory usage (it seems that it is the same for both based on my small tests). The time however is about 7 times slower for the named parameters (because it is actually checking to see if the parameter exists in the array first before creating it). So… if you are calling the function around 100000 times in one script, you probably should not use named parameters because you will notice a slight slowdown.

  • Wayne

    Interesting idea, although I think it will cause more confusion, makes a function call look dirty, and not work as well as named parameters in IDEs like PhpED and Zend Studio.

    Correct me if I am wrong here…

    • http://blog.seanja.com/ SeanJA

      True, it might cause more confusion when you are writing the code (if say you were to make a spelling mistake…), but it does increase the readability of the code when you are quickly reading through it. You win some you lose some I guess… It would be great if they would implement a short hand similar to that of ruby which could be autocompleted by your ide of choice.