Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is allowing a PHP function variable to be either string or array a pattern or anti-pattern?

Coming from C# I'm used to overloading my methods with variably typed parameters. Since you can't do this in PHP, I often create methods such as the example below which accept a variable, then I check the type and act accordingly:

showLength('one');
showLength(array(
    'one',
    'two',
    'three'
));

function showLength($stringOrArray) {
    $arr = array();
    if(is_array($stringOrArray)) {
       $arr = $stringOrArray;
    } else if(is_string($stringOrArray)) {
       $arr[] = $stringOrArray;
    } else {
        //exception
    }
    foreach ($arr as $str) {
        echo strlen($str).'<br/>';
    }
}

output:

3
3
3
5
4

This gives me the same functionality as in C# but it seems a bit messy, as if there is a better way.

Is this the accepted way to do method overloading in PHP (5.3) or is there a better way?

like image 329
Edward Tanguay Avatar asked Jan 20 '11 13:01

Edward Tanguay


2 Answers

I know a lot of frameworks do this for certain functions where it makes sense, as do some of PHP's core functions. The difference between 'good' uses and 'poor' uses to me is the documentation (docblock). The documentation needs to indicate that the param is of type mixed and the different acceptable variable types.

For example:

<?php
/**
  * Function used to assign roles to a user
  * @param int   $user_id The user's id
  * @param mixed $role    Either a string name of the role 
  *                       or an array with string values
  *
  * @return bool on success/failure
  */ 
function addRole($user_id, $role) {
  if (!is_array($role)) {
    $role = array($role);
  }

  foreach($role as item) {
    Model::addRole($item);
  }

  return true;
}
like image 187
Mike B Avatar answered Oct 11 '22 05:10

Mike B


I don't like to beat a dead horse, but still, I'll weigh in here.

I wouldn't consider it an anti-pattern; as @Merijn points out, many native PHP functions accept mixed type parameters. Furthermore, many circumstances as your own, require that for succinctness the function accept an element, or a collection, of a given type instead of splitting it over two functions.

Casting to (array) is a quick and easy way to achieve this functionality:

function printStuff($stuff)
{
    foreach((array) $stuff as $key => $value) {
        echo sprintf('%d : %s', $key, $value) . PHP_EOL;
    }
}

printStuff("foo");
// 0 : foo

printStuff(array("foo", "bar", "qux"));
// 0 : foo
// 1 : bar
// 2 : qux

Using $foo = (array) $foo; is better1 than $foo = array($foo); as when $foo is already an array, it won't wrap it again.


Reference

  • http://php.net/manual/en/language.types.type-juggling.php
  • http://www.php.net/manual/en/language.types.array.php#language.types.array.casting

1 Produces the desired results with scalars; objects produce different results. Objects cast to array will enumerate the properties, so use discretion.

like image 44
Dan Lugg Avatar answered Oct 11 '22 05:10

Dan Lugg