Using static for class default properties
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' =&gt; null,
        'type' =&gt; null,
    );

    private $_current;

    public function __construct(array $defaults = null)
    {
        foreach ($defaults as $key =&gt; $value) {
            if (array_key_exists($this-&gt;_defaults[$key])) {
                $this-&gt;_defaults[$key] = $value;
            }
        }

        $this-&gt;reset();
    }

    public function reset()
    {
        $this-&gt;_current = array();
        foreach ($this-&gt;_defaults as $key =&gt; $value) {
            $this-&gt;_current[$key] = $value;
        }       
    }

    public function setTag($tag)
    {
        if (!is_string($tag)) {
            throw new InvalidArgumentException('...');
        }
        $this-&gt;_current['tag'] = $tag;
    }

    public function setType($type)
    {
        if (!is_string($type)) {
            throw new InvalidArgumentException('...');
        }
        $this-&gt;_current['type'] = $type;    
    }

    public function getInput()
    {
        return new Input($this-&gt;_current);
    }
}


Usage would be:

$builder-&gt;setType('text')
        -&gt;build();  // tag: input, type: text
$builder-&gt;setType('password')
        -&gt;build(); // tag: input, type: password
$builder-&gt;reset(); // reset everything to defaults
$builder-&gt;setTag('textarea') // tag: textarea: type: text
        -&gt;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' =&gt; null,
            'type' =&gt; null,
        );

        private $_current;

        public function __construct(array $defaults = null)
        {
            foreach ($defaults as $key =&gt; $value) {
                if (array_key_exists($this-&gt;_defaults[$key])) {
                    $this-&gt;_defaults[$key] = $value;
                }
            }
        }

        public function configure(Input $element)
        {
            $config = $this-&gt;_init['tag'];

            if (null !== $config['tag'] &amp;&amp; null !== $element-&gt;getTag()) {
                $element-&gt;setTag($config['tag']);
            }

            if (null !== $config['type'] &amp;&amp; null !== $element-&gt;getType()) {
                $element-&gt;setType($config['type']);
            }
        }
}

class Input 
{
     public function construct(InputConfiguration $config = null)
     {
           if (null !== $config) {
               $config-&gt;configure($this);
           }
     }

     // ...
}


Usage would be: 

$configuration = new InputConfiguration(
    'tag' =&gt; 'input', 
    'type' =&gt; 'text',
);

$newObject = new Input($configuration); // has defaults applied

$newObject2 = new Input(); // we don't want to use defaults
$configuration-&gt;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.