Question

I receive an object during some process and this object needs to figure out its coloring scheme. For example, I have a coloring scheme that is stored like this:

class FirstScheme {
    public static $COLORS = array('1' => 'green', '2' => 'red', ...);
}
class SecondScheme {
    public static $COLORS = array('1' => 'red', '2' => 'green', ...);
}

I know all the coloring schemes names in advance; they can only change when the code changes. But the coloring scheme to be used for each object needs to be determined at run-time by matching the attribute of this object.

And here I don't know what to do. In python I would define a dict holding the mappings of color schemes to names like this:

d = {'attr_value1': FirstScheme, 'attr_value2': SecondScheme, 'attr_value3': FirstScheme, ...}

And then just access the "COLORS" variable, because every class should have it. But in PHP there is not way to reference a class in a such way, so what is the right way to do it? Note that more than one attribute can map to the same coloring scheme.

Was it helpful?

Solution

If every class should have the colors, define the interface that allows to get them:

interface ColorsProvider {
    function getColors();
}
class FirstScheme implements ColorsProvider {
    public static COLORS = array('1' => 'green', '2' => 'red', ...);

    public function getColors() {
        return self::COLORS;
    }
}
class SecondScheme implements ColorsProvider {
    public static COLORS = array('1' => 'red', '2' => 'green', ...);

    public function getColors() {
        return self::COLORS;
    }
}

Then, where you have stack of yout params:

$a = array(
  'attr_value1' => new FirstScheme(),
  'attr_value2' => new SecondScheme(),
);

You can call:

$param = 'attr_value1';

if(!isset($a[$param]))
    throw new Exception("undefined param");

if(!($a[$param] instanceof ColorsProvider))
    throw new Exception("Param should point to ColorsProvider");

$a[$param]->getColors();

Please note that it is full-objective. In PHP there are simplier ways to get this effects, but my solution is just elegant.


The another point is the interface completely separates the source of colors. There would be from file, database, xml, hardcoded etc.


Default implementation might be:

abstract class DefaultColorsProviderImpl implements ColorsProvider             {
    protected static COLORS = array();

    public function getColors() {
        return self::COLORS;
    }
}

class FirstScheme extends DefaultColorsProviderImpl {
    protected static COLORS = array( ... );
}

But still allows to make generic implementation that returns colors from e.x. from file.

OTHER TIPS

Of course you can:

$schemes = [
  'attr_value1' => FirstScheme::$COLORS,
  'attr_value2' => SecondScheme::$COLORS,
  ...
];

Or even at runtime:

$schemes = [
  'attr_value1' => 'FirstScheme',
  'attr_value2' => 'SecondScheme',
  ...
];

And then:

$reflector = new ReflectionClass($schemes['attr_value1']);
$schema = $reflector->getStaticPropertyValue('COLORS');

But this seems not any maintainable at all, and you would like to store such informations in a proper data layer, without hardcoding them as static fields of a class [which is not their purpose].

An alternative to hard-coding the colors in their own classes would be the following approach:

class ColorScheme {

   protected $colors;

   public function __construct(array $colors) {
       $this->colors = $colors;
   }

   public function getColors() {
       return $this->colors;
   }

}

$scheme1 = new ColorScheme(array('red', 'blue', 'green'));
$scheme2 = new ColorScheme(array('yellow', 'pink', 'cyan'));

The equivalent for a python dictionary in PHP is an associative array. So you could do this:

$d = array (
    'values_1' => $scheme1->getColors(),
    'values_2' => $scheme2->getColors()
);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top