una poo otro objeto llamar las instancias instancia guardan ejemplos donde desde crear como clases clase archivo php class constructor instantiation idioms

poo - llamar una clase desde otro archivo php



PHP: la mejor forma de inicializar un objeto con una gran cantidad de parámetros y valores predeterminados (6)

Estoy diseñando una clase que define un objeto altamente complejo con una tonelada (más de 50) de parámetros principalmente opcionales, muchos de los cuales tienen valores predeterminados (por ejemplo: $type = ''foo''; $width = ''300''; $interactive = false; ). Estoy tratando de determinar la mejor forma de configurar las variables de constructor e instancia / clase para poder:

  • hacer que sea fácil usar la clase
  • facilite la auto-documentación de la clase (es decir: utilizando phpDocumentor)
  • codificar esto elegantemente

A la luz de lo anterior, no quiero pasarle al constructor una tonelada de argumentos. Le pasaré un solo hash que contiene los valores de inicialización, por ejemplo: $foo = new Foo(array(''type''=>''bar'', ''width''=>300, ''interactive''=>false));

En términos de codificación de la clase, todavía siento que 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 (se obtiene la lista de las propiedades de la clase, que le permite al usuario API saber con qué ''opciones'' tienen que trabajar), y se "siente" como la forma correcta de hacerlo eso.

Pero luego te topas 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, te metes en un enfoque de "fuerza bruta" que para mí derrota el propósito (aunque estoy abierto a otros opiniones). P.ej:

function __construct($args){ if(isset($args[''type''])) $_type = $args[''type'']; // yuck! }

Consideré crear una sola variable de clase que sea ella misma una matriz asociativa. Inicializar esto sería realmente fácil, 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 parece que no estoy aprovechando las características nativas, como las variables de clase privadas, y parece que la generación de documentación no 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?

Anexo (detalles sobre esta Clase en particular)

Es bastante probable que esta clase intente hacer demasiado, pero es un puerto de una antigua biblioteca de Perl para crear y procesar 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.

A pedido, 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 por lo que el usuario puede 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 extenso 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 );


Lo uso en algunas de mis clases. Hace que sea fácil de copiar y pegar para un desarrollo rápido.

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;} }

Pasos para usar:

  1. Pegue y obtenga la lista de variables de su función __construct actual, eliminando cualquier valor de parámetro opcional
  2. Si aún no lo has hecho, pégalo para declarar tus variables para tu clase, usando el alcance que elijas
  3. Pega esa misma línea en las líneas $ varValues ​​y $ varNames.
  4. Reemplace un texto en ", $" por "'',''". Eso conseguirá todo menos el primero y el último que tendrá que cambiar manualmente
  5. ¡Disfrutar!

Otro enfoque es instanciar la clase con un objeto FooOptions , actuando únicamente como un contenedor de opciones:

<?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(); // ... }

Sus opciones están bien documentadas y usted tiene una forma fácil de configurarlas / recuperarlas. Esto incluso facilita su prueba, ya que puede crear y establecer diferentes opciones de objetos.

No recuerdo el nombre exacto de este patrón, pero creo que es un patrón de Builder u Opción .


Puedo pensar en dos formas de hacerlo. Si desea mantener sus variables de instancia, puede iterar a través de la matriz pasada al constructor y establecer dinámicamente la variable de instancia:

<?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; } } } } ?>

Cuando se usa el enfoque de matriz, no es necesario abandonar la documentación. Simplemente use las anotaciones @property en el cuerpo de la clase:

<?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; } } ?>

Dicho esto, una clase con 50 variables miembro solo se usa para la configuración (que se puede dividir) o simplemente está haciendo demasiado y es posible que desee pensar en refactorizarla.


Solo para seguir con la forma en que implementé esto, basado en una de las soluciones de Daff :

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; } } }

Sugerencias de mejora bienvenida!


Solo una pequeña mejora en la primera solución de Daff para soportar propiedades de objetos que pueden tener un valor predeterminado nulo y devolvería FALSE a la condición isset ():

<?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; } } } } ?>


También puedes hacer una clase para padres.

En esa clase solo defines las variables.

protected function _SetVarName( $arg ){ $this->varName=$arg; }

Luego, amplíe esa clase a un nuevo archivo y en ese archivo cree todos sus procesos.

Entonces obtienes

classname.vars.php classname.php classname extends classnameVars { }

Como la mayoría estará en modo predeterminado, solo tiene que configurar / restablecer los que necesita.

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