class - PHP - best way to initialize an object with a large number of parameters and default values -
i'm designing class defines highly complex object ton (50+) of optional parameters, many of have defaults (eg: $type = 'foo'; $width = '300'; $interactive = false;
). i'm trying determine best way set constructor , instance/class variables in order able to:
- make easy use class
- make easy auto-document class (ie: using phpdocumentor)
- code elegantly
in light of above, don't want passing constructor ton of arguments. passing single hash contains initialization values, eg: $foo = new foo(array('type'=>'bar', 'width'=>300, 'interactive'=>false));
in terms of coding class, still feel rather have...
class foo { private $_type = 'default_type'; private $_width = 100; private $_interactive = true; ... }
...because believe facilitate documentation generation (you list of class' properties, lets api user know 'options' have work with), , "feels" right way it.
but run problem of mapping incoming parameters in constructor class variables, , without exploiting symbol table, "brute force" approach me defeats purpose (though i'm open other opinions). e.g.:
function __construct($args){ if(isset($args['type'])) $_type = $args['type']; // yuck! }
i've considered creating single class variable associative array. initializing easy then, e.g.:
private $_instance_params = array( 'type' => 'default_type', 'width' => 100, 'interactive' => true ); function __construct($args){ foreach($args $key=>$value){ $_instance_params[$key] = $value; } }
but seems i'm not taking advantage of native features private class variables, , feels documentation generation not work approach.
thanks reading far; i'm asking lot here, i'm new php , looking idiomatic / elegant way of doing this. best practices?
addendum (details particular class)
it's quite class trying much, port of old perl library creating , processing forms. there's way of dividing configuration options take advantage of inheritance , polymorphism, may counter-productive.
by request, here partial listing of of parameters (perl code). should see these don't map sub-classes.
the class has getters , setters many of these properties user can over-ride them; objective of post (and original code nicely) provide compact way of instantiating these form objects required parameters set. makes readable code.
# form behaviour parameters # -------------------------- $self->{id}; # id , name of <form> tag $self->{name} = "webform"; # legacy - replaced {id} $self->{user_id} = $global->{user_id}; # used make sure links have user id encoded in them. gets returned {'i'} user input parameter $self->{no_form}; # if set, <form> tag omitted $self->{readonly}; # if set, entire form read-only $self->{autosave} = ''; # when set true, un-focusing field causes field data saved $self->{scrubbed}; # if set "true" or non-null, places "changed" radio button on far right of row-per-record forms indicates record has been edited. used allow users edit multiple records @ same time , save results @ once. cool. $self->{add_rowid}; # if set, each row in form have hidden "rowid" input field row_id of record (used scrubbable records). if 'scrubbed' parameter set, parameter automatically set. note work, select statement must pull out unique row id. $self->{row_id_prefix} = "row_"; # each row gets unique id of form id="row_##" ## corresponds record's rowid. in case of multiple forms, if need identify specific row, can change "row_" prefix unique. default it's "row_" $self->{validate_form}; # parses user_input , validates required fields , on form $self->{target}; # adds target window form tag if specified $self->{focus_on_field}; # if supplied, add <script> tag @ end of form set focus on named field once form loads. $self->{on_submit}; # adds onsubmit event handler form tag if supplied $self->{ctrl_s_button_name}; # if supplied name of savebutton, add onkeypress handler process ctrl-s way of saving form # form paging parameters # ---------------------- $self->{max_rows_per_page}; # when displaying complete form using printform() method, determines number of rows shown on screen @ time. if blank or undef, rows in query shown , no header/footer produced. $self->{max_pages_in_nav} = 7; # when displaying navbar above , below list forms, determines how many page links shown. should odd number $self->{current_offset}; # current page we're displaying $self->{total_records}; # number of records returned query $self->{hide_max_rows_selector} = ""; # hide <select> tag allowing users choose max_rows_per_page $self->{force_selected_row} = ""; # if set, calls showpage() clear rowid hidden field on form, forcing first record displayed if none selected $self->{paging_style} = "normal"; # options: "compact"
we can, of course, allow ourselves drawn more lengthy debate around programming style. i'm hoping avoid it, sanity of involved! here (perl code, again) example of instantiating object pretty hefty set of parameters.
my $form = new valz::webform ( id => "dbform", form_name => "user_mailbox_recip_list_students", user_input => \%params, user_id => $params{i}, no_form => "no_form", selectable => "checkbox", selectable_row_prefix => "student", selected_row => join (",", getrecipientidsbytype('student')), this_page => $params{c}, paging_style => "compact", hide_max_rows_selector => 'true', max_pages_in_nav => 5 );
i can think of 2 ways of doing that. if want keep instance variables can iterate through array passed constructor , set instance variable dynamically:
<?php class foo { private $_type = 'default_type'; private $_width = 100; private $_interactive = true; function __construct($args){ foreach($args $key => $val) { $name = '_' . $key; if(isset($this->{$name})) { $this->{$name} = $val; } } } } ?>
when using array approach don't have abandon documentation. use @property annotations in 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, class 50 member variables either used configuration (which can split up) or doing , might want think refactoring it.
Comments
Post a Comment