PHP - best way to initialize an object with a large number of parameters and default values

强颜欢笑 提交于 2019-12-02 17:06:44

I can think of two ways of doing that. If you want to keep your instance variables you can just iterate through the array passed to the constructor and set the instance variable dynamically:

    <?php

    class Foo {
        private $_type = 'default_type';
        private $_width = 100;
        private $_interactive = true;

        function __construct($args){
            foreach($args as $key => $val) {
                $name = '_' . $key;
                if(isset($this->{$name})) {
                    $this->{$name} = $val;
                }
            }
        }
    }

    ?>

When using the array approach you don't really have to abandon documentation. Just use the @property annotations in the class body:

<?php

/**
 * @property string $type
 * @property integer $width
 * @property boolean $interactive
 */
class Foo {
    private $_instance_params = array(
        'type' => 'default_type',
        'width' => 100,
        'interactive' => true
    );

    function __construct($args){
        $this->_instance_params = array_merge_recursive($this->_instance_params, $args);
    }

    public function __get($name)
    {
        return $this->_instance_params[$name];
    }

    public function __set($name, $value)
    {
        $this->_instance_params[$name] = $value;
    }
}

?>

That said, a class with 50 member variables is either only used for configuration (which can be split up) or it is just doing too much and you might want to think about refactoring it.

Another approach is to instantiate the class with a FooOptions object, acting solely as an options container:

<?php
class Foo 
{
    /*
     * @var FooOptions
     */
    private $_options;

    public function __construct(FooOptions $options) 
    {
        $this->_options = $options;
    }
}


class FooOptions
{
    private $_type = 'default_type';
    private $_width = 100;
    private $_interactive = true;

    public function setType($type);
    public function getType();

    public function setWidth($width);
    public function getWidth();

    // ...
}

Your options are well documented and you have an easy way to set/retrieve them. This even facilitates your testing, as you can create and set different options objects.

I don't remember the exact name of this pattern, but I think it's Builder or Option pattern.

Tom Auger

Just to follow up with how I implemented this, based on one of Daff's solutions:

    function __construct($args = array()){
        // build all args into their corresponding class properties
        foreach($args as $key => $val) {                
            // only accept keys that have explicitly been defined as class member variables
            if(property_exists($this, $key)) {
                $this->{$key} = $val;
            }
        }
    }

Improvement suggestions welcomed!

Paolo_Mulder

You also could make a parent class.

In that class you only define the variables.

protected function _SetVarName( $arg ){

   $this->varName=$arg;
}

Then extend that class into a new file and in that file you create all your processes.

So you get

classname.vars.php
classname.php

classname extends classnameVars {

}

Because most will be on default you only have to Set/Reset the ones you need.

$cn=new classname();
$cn->setVar($arg);    
//do your functions..

I use this on a few of my classes. Makes it easy to copy and paste for rapid development.

private $CCNumber, $ExpMonth, $ExpYear, $CV3, $CardType;
function __construct($CCNumber, $ExpMonth, $ExpYear, $CV3, $CardType){
    $varsValues = array($CCNumber, $ExpMonth, $ExpYear, $CV3, $CardType);
    $varNames = array('CCNumber', 'ExpMonth', 'ExpYear', 'CV3', 'CardType');
    $varCombined = array_combine($varNames, $varsValues);
    foreach ($varCombined as $varName => $varValue) {$this->$varName = $varValue;}
}

Steps to use:

  1. Paste in and get the list of variables from your current __construct function, removing any optional parameter values
  2. If you haven't already, paste that in to declare your variables for your class, using the scope of your choosing
  3. Paste that same line into the $varValues and $varNames lines.
  4. Do a text replace on ", $" for "', '". That'll get all but the first and last that you'll have to manually change
  5. Enjoy!

Just a little improvement on Daff's first solution to support object properties that may have a null default value and would return FALSE to the isset() condition:

<?php

class Foo {
    private $_type = 'default_type';
    private $_width = 100;
    private $_interactive = true;
    private $_nullable_par = null;

    function __construct($args){
        foreach($args as $key => $val) {
            $name = '_' . $key;
            if(property_exists(get_called_class(),$name))
                $this->{$name} = $val;
            }
        }
    }
}

?>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!