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

后端 未结 6 1104
旧巷少年郎
旧巷少年郎 2021-01-31 09:20

I\'m designing a class that defines a highly complex object with a ton (50+) of mostly optional parameters, many of which would have defaults (eg: $type = \'foo\'; $width

相关标签:
6条回答
  • 2021-01-31 09:34

    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.

    0 讨论(0)
  • 2021-01-31 09:40

    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!
    0 讨论(0)
  • 2021-01-31 09:49

    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.

    0 讨论(0)
  • 2021-01-31 09:49

    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!

    0 讨论(0)
  • 2021-01-31 09:52

    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;
                }
            }
        }
    }
    
    ?>
    
    0 讨论(0)
  • 2021-01-31 09:59

    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..
    
    0 讨论(0)
提交回复
热议问题