tags:

views:

178

answers:

5

Hi,

In PHP, say that you have some code like this:

$infrastructure = mt_rand(0,100);
if ($infrastructure < $min_infrastructure) $infrastructure = $min_infrastructure;
//do some other stuff with $infrastructure
$country->set_infrastructure($infrastructure);

$education = mt_rand(0,100);
if ($education < $min_education) $education = $min_education;
//do some other stuff with $education
$country->set_education($education);

$healthcare = mt_rand(0,100);
if ($healthcare < $min_healthcare) $healthcare = $min_healthcare;
//do some other stuff with $healthcare
$country->set_healthcare($healthcare);

Is there some way of combining these similar sets of instructions into a function that could be called like:

change_stats("infrastructure");
change_stats("education");
change_stats("healthcare");

Basically, can you use variables in PHP in other variable names and function names?

Thanks in advance.

A: 

I'm not sure about that function but you could do something similar using __set

$data;
function __set($key, $val) {
 $this->data["$key"] = $val;
}

And yes you can use variables dynamically

$foo = "bar";
$dynamic = "foo";

echo $$dynamic; //would output bar
echo $dynamic; //would output foo
lemon
A: 

Yes, it is possible, take a look here for a discussion and here for a tutorial.

luvieere
A: 

Hi Toytown Mafia,

To answer your question: Yes, you can use variables as variable names, using the ${$varname} syntax.

However, that does not seem to be a proper solution for what you are trying to do here, as setting the $the_{$petname} variables requires them to be in the scope of the name_pet function.

Could you elaborate a bit more on what it is that you are trying to do?

Some suggestions: Have the pet class (or whatever it is that the cat, dog and fish are) return the name that is being set, so you can do $fish_name = $the_fish->setName("Goldie");

Or even better, not use $fish_name at all, since that information is now stored in the object... you could simply call $the_fish->getName(); where you'd use $the_fish.

Hope this helps?

kander
+3  A: 

You can use what PHP calls "variable variables" to do this. I hope your example is contrived, as it looks a bit odd, but assuming the variables and objects are global, you could write the name_pet() function like this:

function name_pet($type, $name)
{
    $class='the_'.$type;
    $var=$type.'_name';

    $GLOBALS[$class]->setName($name);
    $GLOBALS[$var]=$name;
}

EDIT: this answer refers to an earlier version of the question.

Paul Dixon
+1 for answering the question directly.The difficulty with variable variables is that they make the code hard to read and to maintain. I avoid them when I write code, and I refactor them away when I find them in code.
Ewan Todd
A: 

This is an interesting question because this is a common pattern and is especially important to watch out for when refactoring.

In the purely functional way, you can use some code like this:

function rand_or_min( $value, $key, $country ) {
  $rand = mt_rand(0,100);
  if ($rand < $value ) { $rand = $value; }
  // do something
  call_user_func( array( $country, 'set_' . $value ), array( $rand ) );
}

$arr = array('infrastructure' => 5,'education' => 3,'healthcare' => 80);
array_walk( $arr, 'rand_or_min', $country );

Though the above works well, I would highly recommend that you use a more object oriented path. Whenever you see a pattern like the above, you should be thinking classes and sub-classes. Why? Because there is duplicated behavior and similar state (variables).

In a more OOP way, this could be implemented like so:

class SomeBasicBehavior {

   function __construct( $min = 0 ) {
      $rand = mt_rand(0,100);
      if( $rand < $min ) { $rand = $min };
      return $rand;
   }

}

class Infrastructure extends SomeBasicBehavior {
}

class Education extends SomeBasicBehavior {
}

class Healthcare extends SomeBasicBehavior {
}

$country->set_infrastructure( new Infrastructure() );
$country->set_education( new Education() };
$country->set_healthcare( new Healthcare() };

Not only is it much more readable, but it's also much more extensible and testable. Your "do something" can be easily implemented as member functions in each class and their behavior can be as shared as needed (using the SomeBasicBehavior class) or as encapsulated as you require.

Pras