Estoy diseñando una clase que define un objeto altamente complejo con una tonelada (50+) de parámetros principalmente opcionales, muchos de los cuales tendrían valores predeterminados (por ejemplo: $type = 'foo'; $width = '300'; $interactive = false;
). Estoy tratando de determinar la mejor manera de configurar el constructor y variables de instancia/clase con el fin de ser capaz de:PHP - la mejor manera de inicializar un objeto con un gran número de parámetros y valores predeterminados
- que sea fácil de utilizar la clase
- facilitan la auto-documento de la clase (es decir: el uso de phpDocumentor) código
- esta elegantemente
En vista de lo anterior, no quiero ser el constructor de pasar un montón de argumentos. Voy a estar pasando un hash único que contiene los valores de inicialización, por ejemplo: $foo = new Foo(array('type'=>'bar', 'width'=>300, 'interactive'=>false));
En cuanto a la codificación de la clase, todavía se siente como yo preferiría tener ...
class Foo {
private $_type = 'default_type';
private $_width = 100;
private $_interactive = true;
...
}
... porque Creo que esto facilitaría la generación de documentación (obtienes la lista de las propiedades de la clase, que le permite al usuario de la API saber con qué 'opciones' tienen que trabajar), y "se siente" como la forma correcta de hacerlo.
Pero luego se encuentra con el problema de mapear los parámetros entrantes en el constructor a las variables de clase, y sin explotar la tabla de símbolos, entra en un enfoque de "fuerza bruta" que me frustra (aunque yo m abierto a otras opiniones). Por ejemplo:
function __construct($args){
if(isset($args['type'])) $_type = $args['type']; // yuck!
}
He considerado crear una sola variable de clase que sea ella misma una matriz asociativa. La inicialización de esto sería muy fácil, entonces, por ejemplo .:
private $_instance_params = array(
'type' => 'default_type',
'width' => 100,
'interactive' => true
);
function __construct($args){
foreach($args as $key=>$value){
$_instance_params[$key] = $value;
}
}
Pero esto parece como si no estuviera tomando ventaja de las características nativas como variables de clases privadas, y se siente como la generación de la documentación no va a funcionar con este enfoque.
Gracias por leer hasta aquí; Probablemente estoy preguntando mucho aquí, pero soy nuevo en PHP y realmente estoy buscando la manera idiomática/elegante de hacer esto. ¿Cuáles son tus mejores prácticas?
Adición (detalles acerca de esta clase en particular)
Es muy probable que esta clase está tratando de hacer demasiado, pero es un puerto de una antigua biblioteca de Perl para la creación y procesamiento de formularios. Probablemente exista una forma de dividir las opciones de configuración para aprovechar la herencia y el polimorfismo, pero en realidad puede ser contraproducente.
Por solicitud, aquí hay una lista parcial de algunos de los parámetros (código de Perl). Debería ver que estos no se asignan muy bien a las subclases.
La clase sin duda tiene getters y setters para muchas de estas propiedades para que el usuario pueda anularlas; el objetivo de esta publicación (y algo que el código original hace muy bien) es proporcionar una forma compacta de instanciar estos objetos Form con los parámetros requeridos ya establecidos. Realmente hace un código muy legible.
# Form Behaviour Parameters
# --------------------------
$self->{id}; # the id and the name of the <form> tag
$self->{name} = "webform"; # legacy - replaced by {id}
$self->{user_id} = $global->{user_id}; # used to make sure that all links have the user id encoded in them. Usually this gets returned as the {'i'} user input parameter
$self->{no_form}; # if set, the <form> tag will be omitted
$self->{readonly}; # if set, the entire form will be read-only
$self->{autosave} = ''; # when set to true, un-focusing a field causes the field data to be saved immediately
$self->{scrubbed}; # if set to "true" or non-null, places a "changed" radio button on far right of row-per-record forms that indicates that a record has been edited. Used to allow users to edit multiple records at the same time and save the results all at once. Very cool.
$self->{add_rowid}; # if set, each row in a form will have a hidden "rowid" input field with the row_id of that record (used primarily for scrubbable records). If the 'scrubbed' parameter is set, this parameter is also automatically set. Note that for this to work, the SELECT statement must pull out a unique row id.
$self->{row_id_prefix} = "row_"; # each row gets a unique id of the form id="row_##" where ## corresponds to the record's rowid. In the case of multiple forms, if we need to identify a specific row, we can change the "row_" prefix to something unique. By default it's "row_"
$self->{validate_form}; # parses user_input and validates required fields and the like on a form
$self->{target}; # adds a target window to the form tag if specified
$self->{focus_on_field}; # if supplied, this will add a <script> tag at the end of the form that will set the focus on the named field once the form loads.
$self->{on_submit}; # adds the onSubmit event handler to the form tag if supplied
$self->{ctrl_s_button_name}; # if supplied with the name of the savebutton, this will add an onKeypress handler to process CTRL-S as a way of saving the form
# Form Paging Parameters
# ----------------------
$self->{max_rows_per_page}; # when displaying a complete form using printForm() method, determines the number of rows shown on screen at a time. If this is blank or undef, then all rows in the query are shown and no header/footer is produced.
$self->{max_pages_in_nav} = 7; # when displaying the navbar above and below list forms, determines how many page links are shown. Should be an odd number
$self->{current_offset}; # the current page that we're displaying
$self->{total_records}; # the number of records returned by the query
$self->{hide_max_rows_selector} = ""; # hide the <select> tag allowing users to choose the max_rows_per_page
$self->{force_selected_row} = ""; # if this is set, calls to showPage() will also clear the rowid hidden field on the form, forcing the first record to be displayed if none were selected
$self->{paging_style} = "normal"; # Options: "compact"
Podemos, por supuesto, permitirnos entablar un debate más prolongado sobre el estilo de programación. ¡Pero espero evitarlo, por la cordura de todos los involucrados! Aquí (código Perl, nuevamente) es un ejemplo de creación de instancia de este objeto con un conjunto de parámetros bastante considerable.
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
);
Esto suena como la clase está haciendo waaaaaaaaay demasiado. ¿Puede elaborar más sobre lo que se supone que debe hacer esta clase y tal vez enumerar algunas o más de las 50 propiedades? – Gordon
¿Cuál es el inconveniente de hacer estos miembros públicos? ¿Necesita que se corrijan después de la construcción y no proporciona ningún otro medio para cambiar los valores? – Mel
@Mel - a menos que esté equivocado, hacer que los miembros sean públicos no mejora la situación. Simplemente alentaría un código feo en el front-end en lugar de en el back-end. –