patternphpMinor
Calling functions with variable functions
Viewed 0 times
withfunctionscallingvariable
Problem
I have some PHP code where I use variable functions to call the right function. I need to build a chart array (for example), and the chart array that comes out has a fixed format. But the data that goes into the chart or table comes from varying places in the underlying objects.
An example:
and then the function gets called something like:
where
This works fine and lets me re-use
Is there a way to refactor this or is there some pattern I can use to avoid them?
An example:
private function buildChartGroups(PropelCollection $groups, $propertyForDisplay) {
$groupDisplayFunction = "getSum$propertyForDisplay";
$chart = array();
foreach ($groups as $group) {
$chart[] = array('name' => $group->getName(),
'y' => $group->$groupDisplayFunction()
);
}
}
return $chart;
}and then the function gets called something like:
$result = $this->buildChartGroups($groups, "Total");
...elsewhere...
$result = $this->buildChartGroups($groups, "Count");where
$groups is an array of Group objects:class Group {
private $name;
private $sumTotal;
private $sumCount;
public function getName() {
return $this->name;
}
public function getSumTotal() {
return $this->sumTotal;
}
public function getSumCount() {
return $this->sumCount;
}
}This works fine and lets me re-use
buildChartGroups() which I would otherwise not be able to do. But using variable functions and passing function names as strings always seems a little dirty, even though I'm sure it has its place.Is there a way to refactor this or is there some pattern I can use to avoid them?
Solution
I agree, it does feel dirty to compute the function name like that.
A typical way to do dynamic dispatching is using polymorphism. You could formalize the mechanism for determining which function to call by making some property-extracting objects:
Your
Here it is in use:
A typical way to do dynamic dispatching is using polymorphism. You could formalize the mechanism for determining which function to call by making some property-extracting objects:
abstract class PropertyExtractor {
public abstract function getProperty($group);
}
class SumTotalExtractor extends PropertyExtractor {
public function getProperty($group) {
return $group->getSumTotal();
}
}
class SumCountExtractor extends PropertyExtractor {
public function getProperty($group) {
return $group->getSumCount();
}
}Your
buildChartGroups() would take one of those extractors as the second parameter:private function buildChartGroups(PropelCollection $groups, $propertyExtractor) {
$chart = array();
foreach ($groups as $group) {
$chart[] = array('name' => $group->getName(),
'y' => $propertyExtractor->getProperty($group));
}
return $chart;
}Here it is in use:
$result = $this->buildChartGroups($groups, new SumTotalExtractor());Code Snippets
abstract class PropertyExtractor {
public abstract function getProperty($group);
}
class SumTotalExtractor extends PropertyExtractor {
public function getProperty($group) {
return $group->getSumTotal();
}
}
class SumCountExtractor extends PropertyExtractor {
public function getProperty($group) {
return $group->getSumCount();
}
}private function buildChartGroups(PropelCollection $groups, $propertyExtractor) {
$chart = array();
foreach ($groups as $group) {
$chart[] = array('name' => $group->getName(),
'y' => $propertyExtractor->getProperty($group));
}
return $chart;
}$result = $this->buildChartGroups($groups, new SumTotalExtractor());Context
StackExchange Code Review Q#46855, answer score: 5
Revisions (0)
No revisions yet.