visual studio setters para getters generate configurar code and php oop coding-style

php - studio - Getter y Setter?



php getter setter generator (16)

No soy un desarrollador de PHP, así que me pregunto si en PHP es más popular usar getter / setters explícitos, en un estilo POO puro, con campos privados (de la manera que me gusta):

class MyClass { private $firstField; private $secondField; public function getFirstField() { return $this->firstField; } public function setFirstField($x) { $this->firstField = $x; } public function getSecondField() { return $this->secondField; } public function setSecondField($x) { $this->secondField = $x; } }

o solo campos públicos:

class MyClass { public $firstField; public $secondField; }

Gracias


Validar + Formatear / Derivar valores

Setters le permiten validar datos y los getters le permiten formatear o derivar datos. Los objetos le permiten encapsular datos y su código de validación y formateo en un paquete ordenado que alienta a DRY.

Por ejemplo, considere la siguiente clase simple que contiene una fecha de nacimiento.

class BirthDate { private $birth_date; public function getBirthDate($format=''Y-m-d'') { //format $birth_date ... //$birth_date = ... return $birth_date; } public function setBirthDate($birth_date) { //if($birth_date is not valid) throw an exception ... $this->birth_date = $birth_date; } public function getAge() { //calculate age ... return $age; } public function getDaysUntilBirthday() { //calculate days until birth days return $days; } }

Querrá validar que el valor que se está configurando es

  • Una fecha válida
  • No en el futuro

Y no desea hacer esta validación en toda su aplicación (o en múltiples aplicaciones para el caso). En cambio, es más fácil hacer que la variable miembro sea protegida o privada (para que el colocador sea el único punto de acceso) y validar en el colocador porque entonces sabrá que el objeto contiene una fecha de nacimiento válida sin importar qué parte del aplicación de la que proviene el objeto y si desea agregar más validación, puede agregarla en un solo lugar.

Es posible que desee agregar varios formateadores que operen en la misma variable miembro, es decir, getAge() y getDaysUntilBirthday() y es posible que desee aplicar un formato configurable en getBirthDate() según la configuración regional. Por lo tanto, prefiero acceder constantemente a los valores a través de getters en lugar de mezclar $date->getAge() con $date->birth_date .

getters y setters también son útiles cuando extiendes objetos. Por ejemplo, supongamos que su aplicación necesita permitir más de 150 fechas de nacimiento en algunos lugares, pero no en otros. Una forma de resolver el problema sin repetir ningún código sería extender el objeto BirthDate y poner la validación adicional en el setter.

class LivingBirthDate extends BirthDate { public function setBirthDate($birth_date) { //if $birth_date is greater than 150 years throw an exception //else pass to parent''s setter return parent::setBirthDate($birth_date); } }


¿Por qué usar getters y setters?

  1. Escalabilidad : es más fácil refactorizar un getter que buscar todas las asignaciones var en un código de proyecto.
  2. Depuración : puede colocar puntos de interrupción en setters y getters.
  3. Cleaner : las funciones mágicas no son una buena solución para escribir menos, su IDE no sugerirá el código. Mejor uso de plantillas para getters de escritura rápida.

Actualización: No use esta respuesta ya que este es un código muy tonto que encontré mientras aprendí. Solo usa getter y setter, es mucho mejor.

Usualmente uso ese nombre de variable como nombre de función y agrego un parámetro opcional a esa función, de modo que cuando el llamador rellena ese parámetro opcional, configúrelo en la propiedad y devuelva $ este objeto (encadenamiento) y luego cuando ese parámetro opcional no especificado por persona que llama, simplemente devuelvo la propiedad a la persona que llama.

Mi ejemplo:

class Model { private $propOne; private $propTwo; public function propOne($propVal = '''') { if ($propVal === '''') { return $this->propOne; } else { $this->propOne = $propVal; return $this; } } public function propTwo($propVal = '''') { if ($propVal === '''') { return $this->propTwo; } else { $this->propTwo = $propVal; return $this; } } }


Además de las respuestas ya excelentes y respetadas aquí, me gustaría ampliar en PHP sin setters / getters.

PHP no tiene sintaxis getter y setter . Proporciona métodos subclase o mágicos para permitir "enganchar" y anular el proceso de búsqueda de propiedades, como señaló Dave .

La magia nos permite a los programadores perezosos hacer más con menos código en un momento en el que participamos activamente en un proyecto y lo conocemos íntimamente, pero generalmente a expensas de la legibilidad.

Rendimiento Todas las funciones innecesarias, que resultan de forzar una arquitectura de código getter / setter-like en PHP, involucran su propio stack-frame de memoria al invocar y están desperdiciando ciclos de CPU.

Legibilidad: la base del código incurre en líneas de código de distensión, lo que afecta a la navegación de código ya que más LOC significa más desplazamiento.

Preferencia: Personalmente, como regla general, tomo el fracaso del análisis de código estático como una señal para evitar ir por el camino mágico mientras los beneficios obvios a largo plazo me eludan en ese momento.

Falacias:

Un argumento común es la legibilidad. Por ejemplo, que $someobject->width es más fácil de leer que $someobject->width() . Sin embargo, a diferencia de la circumference o el width un planeta, que se puede suponer que es static , una instancia de un objeto como $someobject , que requiere una función de ancho, probablemente tome una medida del ancho de la instancia del objeto.
Por lo tanto, la legibilidad aumenta principalmente debido a los esquemas de nomenclatura asertivos y no al ocultar la función que produce un valor de propiedad dado.

__get / __set usa:

  • prevalidación y pre-saneamiento de los valores de las propiedades

  • cadenas, por ejemplo

    " some {mathsobj1->generatelatex} multi line text {mathsobj1->latexoutput} with lots of variables for {mathsobj1->generatelatex} some reason "

    En este caso, generatelatex se adheriría a un esquema de nombres de actionname + methodname

  • casos especiales y obvios

    $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated() $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()

Nota: PHP optó por no implementar la sintaxis getter / setter. No estoy afirmando que los getters / setter son generalmente malos.


Bueno, php tiene métodos mágicos __get, __set, __isset & __unset, que siempre es un comienzo. Desgraciadamente (¿entiendes?) Las propiedades OO son más que métodos mágicos. El principal problema con la implementación de PHP es que se requieren métodos mágicos para todas las propiedades inaccesibles. Lo que significa que tiene que repetirse (por ejemplo, llamando a property_exists ()) en los métodos mágicos para determinar si el nombre es realmente una propiedad de su objeto. Y realmente no puedes resolver este problema general con una clase base a menos que todas tus clases hereden de, por ejemplo. ClassWithProperties, ya que PHP carece de herencia múltiple.

Por el contrario, las nuevas clases de estilo de Python le dan propiedad (), que le permite definir explícitamente todas sus propiedades. C # tiene una sintaxis especial. http://en.wikipedia.org/wiki/Property_(programming)


Después de leer los otros consejos, me inclino a decir que:

Como regla GENÉRICA , no siempre se definirán setters para TODAS las propiedades, especialmente las "internas" (semáforos, indicadores internos ...). Las propiedades de solo lectura no tendrán setters, obviamente, por lo que algunas propiedades solo tendrán getters; ahí es donde __get () viene a reducir el código:

  • define un __get () (getters global mágico) para todas esas propiedades que son parecidas,
  • agruparlos en matrices por lo que:
    • compartirán características comunes: los valores monetarios pueden / aparecerán correctamente formateados, las fechas en un diseño específico (ISO, EE. UU., Intl.), etc.
    • el código en sí puede verificar que solo se están leyendo las propiedades existentes y permitidas usando este método mágico.
    • cada vez que necesite crear una propiedad similar nueva, solo tiene que declararla y agregar su nombre a la matriz adecuada y listo. Eso es mucho MÁS RÁPIDO que definir un nuevo getter, quizás con algunas líneas de código REPETIDAS una y otra vez en todo el código de clase.

¡Sí! también podríamos escribir un método privado para hacer eso, pero, una vez más, tendremos MUCHOS métodos declarados (memoria ++) que terminarán llamando a otro método, siempre el mismo. ¿Por qué simplemente no escribir un único método para gobernarlos a todos ...? [¡Sí! juego de palabras absolutamente destinado! :)]

Los setters mágicos también pueden responder SÓLO a propiedades específicas, por lo que todas las propiedades de tipo de fecha se pueden seleccionar contra valores no válidos en un solo método. Si las propiedades del tipo de fecha se enumeraron en una matriz, sus definidores se pueden definir fácilmente. Solo un ejemplo, por supuesto. hay demasiadas situaciones

Acerca de la legibilidad ... Bueno ... Ese es otro debate: no me gusta estar obligado a los usos de un IDE (de hecho, no los uso, tienden a decirme (y me obligan ) a cómo escribe ... y tengo mis gustos sobre codificar "belleza"). Tiendo a ser consecuente con los nombres, así que usar ctags y un par de otras ayudas es suficiente para mí ... En fin: una vez que todos estos setters y getters mágicos terminen, escribo los otros setters que son demasiado específicos o "especiales" para generalizarse en un método __set (). Y eso cubre todo lo que necesito para obtener y establecer propiedades. Por supuesto: no siempre hay un terreno común, o hay unas pocas propiedades que no valen la pena de codificar un método mágico, y aún queda el viejo y tradicional par setter / getter tradicional.

Los lenguajes de programación son solo eso: lenguajes artificiales humanos. Entonces, cada uno de ellos tiene su propia entonación o acento, sintaxis y sabor, por lo que no pretenderé escribir un código de Ruby o Python usando el mismo "acento" que Java o C #, ni escribiría un JavaScript o PHP para parecerme Perl o SQL ... Úselos de la forma en que deben ser utilizados.


En términos generales, la primera forma es más popular en general porque aquellos con conocimientos previos de programación pueden pasar fácilmente a PHP y realizar el trabajo de forma orientada a objetos. La primera forma es más universal. Mi consejo sería seguir con lo que es probado y verdadero en muchos idiomas. Entonces, cuando y si usa otro idioma, estará listo para lograr algo (en lugar de perder tiempo reinventando la rueda ).


Esta publicación no trata específicamente de __get y __set sino __call que es la misma idea, excepto la llamada a un método. Como regla, me mantengo alejado de cualquier tipo de métodos mágicos que permitan la sobrecarga por los motivos descritos en los comentarios y publicaciones. SIN EMBARGO , recientemente me encontré con una API de terceros que uso que usa un SERVICIO y un SUB-SERVICIO, por ejemplo :

http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234

La parte importante de esto es que esta API tiene todo lo mismo excepto la doActionOne , en este caso doActionOne . La idea es que el desarrollador (yo mismo y otros usuarios de esta clase) puedan llamar al subservicio por su nombre en lugar de a algo como:

$myClass->doAction(array(''service''=>''doActionOne'',''args''=>$args));

Podría hacerlo en cambio

$myClass->doActionOne($args);

Para codificar esto, sería una gran cantidad de duplicaciones (este ejemplo se parece mucho al código):

public function doActionOne($array) { $this->args = $array; $name = __FUNCTION__; $this->response = $this->executeCoreCall("APIService.{$name}"); } public function doActionTwo($array) { $this->args = $array; $name = __FUNCTION__; $this->response = $this->executeCoreCall("APIService.{$name}"); } public function doActionThree($array) { $this->args = $array; $name = __FUNCTION__; $this->response = $this->executeCoreCall("APIService.{$name}"); } protected function executeCoreCall($service) { $cURL = new /cURL(); return $cURL->(''http://3rdparty.api.com?service=''.$service.''&apikey=''.$this->api.''&''.http_build_query($this->args)) ->getResponse(); }

Pero con el método mágico de __call() puedo acceder a todos los servicios con métodos dinámicos:

public function __call($name, $arguments) { $this->args = $arguments; $this->response = $this->executeCoreCall("APIService.{$name}"); return $this; }

El beneficio de esta llamada dinámica para la devolución de datos es que si el proveedor agrega otro subservicio, no tengo que agregar otro método en la clase o crear una clase extendida, etc. No estoy seguro de si esto es útil para cualquiera, pero pensé que mostraría un ejemplo donde __set , __get , __call , etc. pueden ser una opción para considerar, ya que la función principal es la devolución de datos.

EDITAR:

Casualmente, vi esto unos días después de la publicación, que describe exactamente mi situación. No es la API a la que me refería, pero la aplicación de los métodos es idéntica:

¿Estoy usando api correctamente?


Getter y setter en PHP

<?php class Car { public $color; public $model; public function Model() { return $this->color; } public function New_Model(){ return $this->model = "BMW CAR HERE"; } } $obj = new Car(); echo $obj->color = "red"; //set color in $color variable echo $obj->New_Model(); //get value from New_Model function echo $obj->Model("red"); //set color in function Model ?>


Google ya publicó una guía de optimización de PHP y la conclusión fue:

Sin getter y setter Optimización de PHP

Y no, no debes usar métodos mágicos . Para PHP, el Método Mágico es malo. ¿Por qué?

  1. Es difícil de depurar.
  2. Existe un impacto en el rendimiento.
  3. Agrega más código

PHP no es ni Java, ni C ++ o C #, PHP es diferente y juega con roles diferentes.


Hay muchas maneras de crear código fuente en una convención de netbeans. Esto es bonito. Hace pensar que tal easyer === FALSE. Simplemente use el tradicional, especialmente si no está seguro de cuál de las propiedades debe encapsularse y cuál no. Lo sé, es un código boi ... pla ..., pero para depurar trabajos y muchos otros piensa que es la mejor y más clara. No dedique mucho tiempo con miles de artes a hacer getters y setters simples. No puede implementar también algunos patrones de diseño como la regla demeter y demás, si usa magia. En una situación específica, puede usar magic_calls o para soluciones pequeñas, rápidas y claras. Claro que también podría hacer soluciones para patrones de diseño de esta manera, pero por qué hacerlo vivir más difícil.


Hice un experimento usando el método mágico __call. No estoy seguro si debería publicarlo (debido a todas las advertencias de "NO USAR MÉTODOS MÁGICOS" en las otras respuestas y comentarios) pero lo dejo aquí ... en caso de que alguien lo encuentre útil.

public function __call($_name, $_arguments){ $action = substr($_name, 0, 4); $varName = substr($_name, 4); if (isset($this->{$varName})){ if ($action === "get_") return $this->{$varName}; if ($action === "set_") $this->{$varName} = $_arguments[0]; } }

Solo agregue el método anterior en su clase, ahora puede escribir:

class MyClass{ private foo = "bar"; private bom = "bim"; // ... // public function __call(){ ... } // ... } $C = new MyClass(); // as getter $C->get_foo(); // return "bar" $C->get_bom(); // return "bim" // as setter $C->set_foo("abc"); // set "abc" as new value of foo $C->set_bom("zam"); // set "zam" as new value of bom

De esta forma, puede obtener / configurar todo en su clase, si existe, de modo que, si lo necesita solo para algunos elementos específicos, podría usar una "lista blanca" como filtro.

Ejemplo:

private $callWhiteList = array( "foo" => "foo", "fee" => "fee", // ... ); public function __call($_name, $_arguments){ $action = substr($_name, 0, 4); $varName = $this->callWhiteList[substr($_name, 4)]; if (!is_null($varName) && isset($this->{$varName})){ if ($action === "get_") return $this->{$varName}; if ($action === "set_") $this->{$varName} = $_arguments[0]; } }

Ahora solo puedes obtener / configurar "foo" y "tarifa".
También puede usar esa "lista blanca" para asignar nombres personalizados para acceder a sus vars.
Por ejemplo,

private $callWhiteList = array( "myfoo" => "foo", "zim" => "bom", // ... );

Con esa lista ahora puede escribir:

class MyClass{ private foo = "bar"; private bom = "bim"; // ... // private $callWhiteList = array( ... ) // public function __call(){ ... } // ... } $C = new MyClass(); // as getter $C->get_myfoo(); // return "bar" $C->get_zim(); // return "bim" // as setter $C->set_myfoo("abc"); // set "abc" as new value of foo $C->set_zim("zam"); // set "zam" as new value of bom

.
.
.
Eso es todo.

Doc: __call() se desencadena al invocar métodos inaccesibles en un contexto de objeto.


La encapsulación es importante en cualquier lenguaje OO, la popularidad no tiene nada que ver con eso. En los lenguajes de tipado dinámico, como PHP, es especialmente útil porque hay pocas maneras de garantizar que una propiedad sea de un tipo específico sin usar setters.

En PHP, esto funciona:

class Foo { public $bar; // should be an integer } $foo = new Foo; $foo->bar = "string";

En Java, no:

class Foo { public int bar; } Foo myFoo = new Foo(); myFoo.bar = "string"; // error

El uso de métodos mágicos ( __get y __set ) también funciona, pero solo cuando se accede a una propiedad que tiene una visibilidad menor a la que puede acceder el alcance actual. Le puede dar dolores de cabeza fácilmente cuando intenta depurar, si no se usa correctamente.


Puedes usar los métodos de php magic __get y __set .

<?php class MyClass { private $firstField; private $secondField; public function __get($property) { if (property_exists($this, $property)) { return $this->$property; } } public function __set($property, $value) { if (property_exists($this, $property)) { $this->$property = $value; } return $this; } } ?>


Si prefiere usar la función __call, puede usar este método. Funciona con

  • GET => $this->property()
  • SET => $this->property($value)
  • GET => $this->getProperty()
  • SET => $this->setProperty($value)

kalsdas

public function __call($name, $arguments) { //Getting and setting with $this->property($optional); if (property_exists(get_class($this), $name)) { //Always set the value if a parameter is passed if (count($arguments) == 1) { /* set */ $this->$name = $arguments[0]; } else if (count($arguments) > 1) { throw new /Exception("Setter for $name only accepts one parameter."); } //Always return the value (Even on the set) return $this->$name; } //If it doesn''t chech if its a normal old type setter ot getter //Getting and setting with $this->getProperty($optional); //Getting and setting with $this->setProperty($optional); $prefix = substr($name, 0, 3); $property = strtolower($name[3]) . substr($name, 4); switch ($prefix) { case ''get'': return $this->$property; break; case ''set'': //Always set the value if a parameter is passed if (count($arguments) != 1) { throw new /Exception("Setter for $name requires exactly one parameter."); } $this->$property = $arguments[0]; //Always return the value (Even on the set) return $this->$name; default: throw new /Exception("Property $name doesn''t exist."); break; } }


class MyClass { private $firstField; private $secondField; private $thirdField; public function __get( $name ) { if( method_exists( $this , $method = ( ''get'' . ucfirst( $name ) ) ) ) return $this->$method(); else throw new Exception( ''Can/'t get property '' . $name ); } public function __set( $name , $value ) { if( method_exists( $this , $method = ( ''set'' . ucfirst( $name ) ) ) ) return $this->$method( $value ); else throw new Exception( ''Can/'t set property '' . $name ); } public function __isset( $name ) { return method_exists( $this , ''get'' . ucfirst( $name ) ) || method_exists( $this , ''set'' . ucfirst( $name ) ); } public function getFirstField() { return $this->firstField; } protected function setFirstField($x) { $this->firstField = $x; } private function getSecondField() { return $this->secondField; } } $obj = new MyClass(); echo $obj->firstField; // works $obj->firstField = ''value''; // works echo $obj->getFirstField(); // works $obj->setFirstField( ''value'' ); // not works, method is protected echo $obj->secondField; // works echo $obj->getSecondField(); // not works, method is private $obj->secondField = ''value''; // not works, setter not exists echo $obj->thirdField; // not works, property not exists isset( $obj->firstField ); // returns true isset( $obj->secondField ); // returns true isset( $obj->thirdField ); // returns false

¡Listo!