I have made a class for generating html form elements:
class input
{
public $tag = 'input', $type = 'text', $customClass, $name;
public function __construct(array $cfg){
if ( isset($cfg['name']) ){
if ( isset($cfg['tag']){
$this->tag = strtolower($cfg['tag']);
}
if ( $this->tag === 'input' && isset($cfg['type']){
$this->type = $cfg['type'];
}
if ( isset($cfg['customClass']){
$this->customClass= $cfg['customClass'];
}
//etc...
}
}
}
I would like to be able to set a custom default config for all my fields - without changing the class. For example I want all the fields in a given script to have 'myClass' as customClass. For me, the solution would be to make these default values static, and make a function to change them like this:
class input
{
static $tag = 'input', $type = 'text', $customClass, $name;
public static function setDefault(array $cfg){
if ( isset($cfg['tag']) ){
self::tag = strtolower($cfg['tag']);
}
if ( isset($cfg['type']) ){
self::type = $cfg['type'];
}
if ( isset($cfg['customClass']) ){
self::customClass= $cfg['customClass'];
}
//etc...
}
public function __construct(array $cfg){
if ( isset($cfg['name']) ){
$this->tag = isset($cfg['tag']) ? strtolower($cfg['tag']) : self::tag;
$this->type = isset($cfg['type']) ? strtolower($cfg['type']) : self::type;
$this->customClass = isset($cfg['customClass']) ? $cfg['customClass'] : self::customClass;
//etc...
}
}
}
The problem is that I read everywhere - and particulary here - that static are evil. What other solution would be suitable in the present case? Or can someone tell me "yeah, that's the perfect case to use statics!"? :)
-
\$\begingroup\$ some further information on how the class is used / in which context / which other components you do have regarding configuration etc... would be helpful. AFAIK there are many very clean solutions. However they highly depend on the available infrastructure and use-cases. \$\endgroup\$Fge– Fge2012年12月12日 14:13:08 +00:00Commented Dec 12, 2012 at 14:13
-
\$\begingroup\$ I'm using a custom MVC framework, but I'd like this class to work as stand-alone, although I plan to use it with another class generating form from database table structure. \$\endgroup\$Nabab– Nabab2012年12月12日 14:16:50 +00:00Commented Dec 12, 2012 at 14:16
1 Answer 1
You could either a configuration object or a builder for this. As you probably can see yourself, using static gets complicated quite fast.
Using a builder:
class InputBuilder
{
private $_defaults = array(
'tag' => null,
'type' => null,
);
private $_current;
public function __construct(array $defaults = null)
{
foreach ($defaults as $key => $value) {
if (array_key_exists($this->_defaults[$key])) {
$this->_defaults[$key] = $value;
}
}
$this->reset();
}
public function reset()
{
$this->_current = array();
foreach ($this->_defaults as $key => $value) {
$this->_current[$key] = $value;
}
}
public function setTag($tag)
{
if (!is_string($tag)) {
throw new InvalidArgumentException('...');
}
$this->_current['tag'] = $tag;
}
public function setType($type)
{
if (!is_string($type)) {
throw new InvalidArgumentException('...');
}
$this->_current['type'] = $type;
}
public function getInput()
{
return new Input($this->_current);
}
}
Usage would be:
$builder->setType('text')
->build(); // tag: input, type: text
$builder->setType('password')
->build(); // tag: input, type: password
$builder->reset(); // reset everything to defaults
$builder->setTag('textarea') // tag: textarea: type: text
->build();
The builder pattern is extremely strong if you want to build the object programmatically. (SQL) Query-builder are a very common use case for this.
Using a configuration object:
class InputConfiguration
{
private $_init = array(
'tag' => null,
'type' => null,
);
private $_current;
public function __construct(array $defaults = null)
{
foreach ($defaults as $key => $value) {
if (array_key_exists($this->_defaults[$key])) {
$this->_defaults[$key] = $value;
}
}
}
public function configure(Input $element)
{
$config = $this->_init['tag'];
if (null !== $config['tag'] && null !== $element->getTag()) {
$element->setTag($config['tag']);
}
if (null !== $config['type'] && null !== $element->getType()) {
$element->setType($config['type']);
}
}
}
class Input
{
public function construct(InputConfiguration $config = null)
{
if (null !== $config) {
$config->configure($this);
}
}
// ...
}
Usage would be:
$configuration = new InputConfiguration(
'tag' => 'input',
'type' => 'text',
);
$newObject = new Input($configuration); // has defaults applied
$newObject2 = new Input(); // we don't want to use defaults
$configuration->configure($newObject2); // or decide to apply them later on
The configuration object decouples the configuration from your object. Furthermore it makes one configuration reusable and optional.
-
\$\begingroup\$ Thanks, that looks like a good implementation. What I prefered in mine is there was only one class - so 1 file included but that's detail. Yes, I think a builder would be the solution for me. Still, why do you say "using static gets complicated quite fast"? \$\endgroup\$Nabab– Nabab2012年12月12日 18:34:12 +00:00Commented Dec 12, 2012 at 18:34
-
\$\begingroup\$ because you maintain almost the same information twice within the class + the class is responsible for knowing two thinks: the defaults and the current data. Look at your code above - in my opinion it's already overly complicated ;) \$\endgroup\$Fge– Fge2012年12月12日 20:25:07 +00:00Commented Dec 12, 2012 at 20:25