tags:

views:

685

answers:

6

I have this simple function which I pass in an array of strings:

function myfunction( $arg = array() )
{
    // do stuff to $arg...
    // return a $string;
}

Simple so far, but I need some of the strings in the $arg array to be formatted, while some remain unformatted. I can't figure out how to do it?

Say I run this $arg through myfunction():

echo myfunction( array( 'format me!', 'do not format me!' ) );

My tiny little brain can't figure out how to tell myfunction() that the first value in $arg array needs to have formatting, and it should not format the second value.

I thought about an associative array, but I think that could be the wrong approach because of having identical indexes.

echo myfunction( array( 'format' => 'hi', 'format' => 'bye', 'noformat' => 'foo');

Just looking for a "nudge" in the right direction.

EDIT 1:

Forgot to mention, I can only have one $arg array because I need the keys to be in a specific order.

EDIT 2:

The $arg array can have as many keys as the user wants.

+1  A: 

Instead of having myfunction() take an array as an argument, why not just have it take a single element as the argument. Then you can use array_map to process each element of the array.

Sort of like this:

function myfunction($element) {
  if( do-formatting) {
    //do your formatting stuff
    $element = formatted-stuff
  }

  return $element
}

$arr = array("format me", "don't format me");

//This calls myfunction on each element of the array
//A new array is returned where each element has been replaced
//by the return value from myfunction.  
$arr = array_map('myfunction', $arr);
Mark Biek
You've just moved the question; now, how do you tell the function whether to format each individual $element?
meagar
I guess that depends on if the array only ever has 2 elements. That wasn't clear to me from the question
Mark Biek
+2  A: 

You can do:

function myfunction(array $format, array $noformat) {
  ... 
}

or

function myfunction(array $strings) {
  foreach ($strings['format'] as $format) {
    // do stuff
  }
  foreach ($strings['noformat'] as $noformat) {
    // do stuff
  }
}

with:

myfunction(array(
  'format' => array('one', 'two', 'three'),
  'noformat' => array('four', 'five', 'six'),
));

If (and only if) the strings are unique you can put them in the key instead of the value:

$strings = array(
  'one' => true,
  'two' => false,
  'three' => false,
  'four' => true,
);

myfunction($strings);

with:

function myfunction(array $strings) {
  foreach ($strings as $k => $v) {
    if ($v) {
      // format string
    }
  }
}

But since you can't have duplicate keys this method falls down if you have repeated strings.

cletus
That is a good answer, but I forgot to mention that I need the `$args` to be in a specific order, so I cannot do a separate `$format` and a `$noformat`.
Jeff
you could use e.g. array(array('format' => 'text'), array('noformat' => 'more text')) as $arg and change the myfunction to accept this as argument (the hint would be foreach ($arg as $formatKey => $text))
jodorovski
The "if (and only if)..." edit looks good! I think I'll give that a whirl. =)
Jeff
Maybe this should be a new question, but how do you test an array to make sure all keys are unique?
Jeff
All keys are unique by definition. If you try and insert the same key it overwrites the old value.
cletus
Good solution for somebody who doesn't mind abusing arrays.
Kevin
The solution for me was to use the key as my string and set whether or not formatting should be performed as (bool) in the element's value. Works perfectly, and I'm not worried about duplicate key names as I am in control of the input.
Jeff
A: 

If you only need to support two variables inside that array, this will work:

function myFunction($arr) {
    $formatThis = array_shift($arr);
    $dontFormat = array_shift($arr);

    // Do the formatting required

    return array($formatThis, $dontFormat);
}
Tatu Ulmanen
A: 

This is oddly similar to how table rows are formatted (with a different formatting function for each row). I would provide the data as a single array, then provide formatting information as a second array based on keys. For instance:

function rowFormatter(Array $data, Array $format=array()) {
  ob_start();
  foreach ($data as $key => $value) {
    if (isset($format[$key])) 
      echo call_user_func($format[$key],$value);
    else 
      echo $value;
  }
  return ob_get_clean();
}

function makeBold($x) { return '<b>'.$x.'</b>'; }

rowFormatter(array( "Hello", "Mister" ), array( 0 => 'makeBold' ));
Victor Nicollet
A: 

I don't know what these strings you are formatting actually represent, so I used generic naming on these classes:

class LineItem
{
    var $value;

    function __construct($val)
    {
        $this->value = $val;
    }

    function __toString()
    {
        return $this->value;
    }

    function getFormatted( $formatter )
    {
        return $this->value;
    }
}

class FormattedLineItem extends LineItem
{
    function getFormatted( $formatter )
    {
        return $formatter( $this->value );
    }
}

function myfunction( $arr=array() )
{
    $fnFormat = function($str) {
        return ucwords($str);
    };

    foreach($arr as $obj)
    {
        $str = $obj->getFormatted($fnFormat);
        echo "$str\n";
    }
}

$arr = array(
    new FormattedLineItem('format me!'),
    new LineItem('do not format me!')
);

myfunction($arr);

The idea is to use separate classes to distinguish between strings.

Kevin
+1  A: 

Here is how I would to it. The implementation of __tostring is not mandatory but is syntax sugar inside the myFunction.

<?php
class MyString{
    private $_value;
    public $to_format;

    public function __construct($str, $to_format = true){
        $this->_value = $str;
        $this->to_format = $to_format;
    }

    public function __tostring(){
        return $this->_value;
    }
}

$args = array( new MyString('format me'), new MyString('Not me!', false) );
Benoit Vidis