1
\$\begingroup\$

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!"? :)

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Dec 12, 2012 at 13:17
\$\endgroup\$
2
  • \$\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\$ Commented 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\$ Commented Dec 12, 2012 at 14:16

1 Answer 1

1
\$\begingroup\$

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.

answered Dec 12, 2012 at 15:30
\$\endgroup\$
2
  • \$\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\$ Commented 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\$ Commented Dec 12, 2012 at 20:25

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.