No soy un desarrollador de PHP, por lo que me pregunto si en PHP es más popular usar getter / setters explícitos, en un estilo OOP puro, con campos privados (como a mí 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
php
oop
coding-style
marca
fuente
fuente
Respuestas:
Puedes usar métodos mágicos
__get
y php__set
.fuente
__get
y__set
. Hay dos guiones bajos, no uno. Aquí está el enlace directo a la parte derecha de la página: php.net/manual/en/… (+1 para una respuesta correcta)public
propiedades, si no hay validación / saneamiento?¿Por qué usar getters y setters?
fuente
Google ya publicó una guía sobre la optimización de PHP y la conclusión fue:
Sin getter y setter Optimizando PHP
Y no, no debes usar métodos mágicos . Para PHP, los métodos mágicos son malos. ¿Por qué?
PHP no es Java, C ++ o C #. PHP es diferente y juega con diferentes roles.
fuente
$dog->name = 'fido'
es mejor que$dog->setName('fido')
. Cuando realmente mute una propiedad (por ejemplo:$dog->increaseAge(1)
puedo construir el método que hace la validación necesaria y muta esa propiedad. Pero no todas las acciones realmente requieren mutación en ese sentido.La encapsulación es importante en cualquier lenguaje OO, la popularidad no tiene nada que ver con eso. En lenguajes de tipo dinámico, como PHP, es especialmente útil porque hay pocas formas de garantizar que una propiedad sea de un tipo específico sin usar setters.
En PHP, esto funciona:
En Java, no:
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 inferior a la que puede acceder el alcance actual. Puede causarle dolores de cabeza fácilmente cuando intenta depurar, si no se usa correctamente.fuente
$bar
comoint
en el primer ejemplo: wiki.php.net/rfc/typed_properties_v2Si prefiere usar la función __call, puede usar este método. Funciona con
$this->property()
$this->property($value)
$this->getProperty()
$this->setProperty($value)
kalsdas
fuente
property_exists(get_class($this), $name)
y la recursividad es lenta. Hay una manera de mitigar esto con el almacenamiento en caché, pero aún será más lento que crear los captadores y establecedores a mano. Solo escribí esto como una alternativa. En realidad no recomiendo usar "Métodos mágicos". El tiempo extra de crear los captadores y establecedores suele ser insignificante.Además de las respuestas ya excelentes y respetadas aquí, me gustaría expandirme en PHP que no tiene setters / getters.
PHP no tiene sintaxis getter y setter . Proporcionamétodossubclases o mágicos para permitir "enganchar" y anular el proceso de búsqueda de propiedades, como señaló Dave .
Magic 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 Cada función innecesaria, que resulta de forzar una arquitectura de código tipo getter / setter en PHP, involucra su propio marco de pila de memoria al invocarlo y está desperdiciando ciclos de CPU.
Legibilidad: la base de código incurre en líneas de código hinchadas, lo que afecta la navegación de código, ya que más LOC significa más desplazamiento.
Preferencia: Personalmente, como regla general, tomo la falla del análisis de código estático como una señal para evitar seguir el camino mágico siempre que los obvios beneficios a largo plazo se me escapen en ese momento.
Falacias:
Un argumento común es la legibilidad. Por ejemplo, eso
$someobject->width
es más fácil de leer que$someobject->width()
. Sin embargo, a diferencia de un planetacircumference
owidth
, que se puede suponer que esstatic
, la 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 esquemas de nombres asertivos y no al ocultar la función que genera un valor de propiedad dado.
__get / __set utiliza:
prevalidación y pre-saneamiento de valores de propiedad
cadenas por ejemplo
En este caso
generatelatex
se adheriría a un esquema de nombres de actionname + methodnamecasos especiales y obvios
Nota: PHP eligió no implementar la sintaxis getter / setter. No estoy afirmando que getters / setter sean generalmente malos.
fuente
¡Listo!
fuente
Bueno, PHP tiene métodos mágicos
__get
,__set
,__isset
y__unset
, lo que es siempre un comienzo. Por desgracia, las propiedades de OO (¿entiendes?) 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 debe repetirse (por ejemplo, llamando a property_exists ()) en los métodos mágicos al determinar si el nombre es realmente una propiedad de su objeto. Y realmente no puede resolver este problema general con una clase base a menos que todas sus clases hereden de ie. ClassWithProperties, ya que PHP carece de herencia múltiple.Por el contrario, Python le ofrece nuevas clases de estilo
property()
, que le permiten definir explícitamente todas sus propiedades. C # tiene una sintaxis especial.http://en.wikipedia.org/wiki/Property_(programming)
fuente
Hice un experimento usando el método mágico __call. No estoy seguro de si debería publicarlo (debido a todas las advertencias de "NO UTILIZAR MÉTODOS MÁGICOS" en las otras respuestas y comentarios) pero lo dejaré aquí ... en caso de que alguien lo encuentre útil.
Simplemente agregue ese método arriba en su clase, ahora puede escribir:
De esta manera, puede obtener / configurar todo en su clase si existe, si lo necesita solo para unos pocos elementos específicos, puede usar una "lista blanca" como filtro.
Ejemplo:
Ahora solo puede obtener / configurar "foo" y "fee".
También puede usar esa "lista blanca" para asignar nombres personalizados para acceder a sus variables.
Por ejemplo,
Con esa lista ahora puede escribir:
.
.
.
Eso es todo.
Doc: __call () se activa al invocar métodos inaccesibles en un contexto de objeto.
fuente
Después de leer los otros consejos, me inclino a decir que:
Como regla GENÉRICA , no siempre definirá definidores para TODAS las propiedades, especialmente las "internas" (semáforos, marcas internas ...). Las propiedades de solo lectura no tendrán setters, obviamente, por lo que algunas propiedades solo tendrán getters; ahí es donde __get () llega a reducir el código:
¡Si! podríamos escribir un método privado para hacer eso, también, pero de nuevo, tendremos MUCHOS métodos declarados (memoria ++) que terminan llamando a otro método, siempre el mismo. ¿Por qué no escribir una SOLA método para gobernarlos a todos ...? [¡Sí! juego de palabras absolutamente previsto! :)]
Los establecedores de magia también pueden responder SOLAMENTE 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 de tipo de fecha se enumeran en una matriz, sus definidores se pueden definir fácilmente. Solo un ejemplo, por supuesto. Hay demasiadas situaciones.
Sobre la legibilidad ... Bueno ... Eso es otro debate: no me gusta estar vinculado a los usos de un IDE (de hecho, yo no uso de ellos, tienden a decirme (y obligar a mí) cómo escribir ... y tengo mis gustos sobre la codificación de "belleza"). Tiendo a ser coherente con los nombres, por lo que usar ctags y un par de otras ayudas es suficiente para mí ... De todos modos: una vez que todos estos setters y getters mágicos están listos, escribo los otros setters que son demasiado específicos o "especiales" para se generalizará en un método __set (). Y eso cubre todo lo que necesito para obtener y configurar propiedades. Por supuesto: no siempre hay un terreno en común, o hay unas pocas propiedades que no merecen la molestia de codificar un método mágico, y luego sigue existiendo el viejo buen 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 pretendo escribir un código Ruby o Python usando el mismo "acento" que Java o C #, ni escribiría un JavaScript o PHP para parecerse Perl o SQL ... Úselos de la forma en que están destinados a ser utilizados.
fuente
En términos generales, la primera forma es más popular en general porque aquellos con conocimientos previos de programación pueden fácilmente pasar a PHP y realizar el trabajo de manera orientada a objetos. La primera forma es más universal. Mi consejo sería seguir con lo que se prueba y es verdadero en muchos idiomas. Luego, cuando y si usa otro idioma, estará listo para lograr algo (en lugar de perder tiempo reinventando la rueda ).
fuente
Hay muchas formas de crear código fuente en una convención netbeans. Esto es bonito. Hace pensar que es más fácil === FALSO. 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 trabajos de depuración y muchos otros piensan que es la mejor manera, clara. No pase mucho tiempo con miles de artes cómo hacer captadores y colocadores simples. No puede implementar también algunos patrones de diseño como la regla demeter y así sucesivamente, 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é hacer que su vida sea más difícil.
fuente
Validar + formatear / derivar valores
Los 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 formato en un paquete ordenado que fomenta DRY.
Por ejemplo, considere la siguiente clase simple que contiene una fecha de nacimiento.
Deberá validar que el valor establecido sea
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 esté protegida o privada (para que el configurador sea el único punto de acceso) y validar en el configurador porque entonces sabrá que el objeto contiene una fecha de nacimiento válida, sin importar qué parte del aplicación del objeto proviene y si desea agregar más validación, puede agregarlo en un solo lugar.
Es posible que desee agregar varios formateadores que operan en la misma, es decir variable miembro
getAge()
ygetDaysUntilBirthday()
y es posible que desee hacer cumplir un formato configurablegetBirthDate()
según la zona. Por lo tanto, prefiero el acceso consistentemente valores a través de captadores en lugar de mezclar$date->getAge()
con$date->birth_date
.getters y setters también son útiles cuando extiendes objetos. Por ejemplo, suponga que su solicitud necesita permitir fechas de nacimiento de más de 150 años en algunos lugares pero no en otros. Una forma de resolver el problema sin repetir ningún código sería extender el
BirthDate
objeto y colocar la validación adicional en el setter.fuente
setHired
ysetHireDate
. No es válido permitir que alguien establezca una fecha de contratación sin también establecer al empleado como contratado. Pero no hay forma de que hagas cumplir esto. Si lo aplica en uno de estos configuradores, entonces está forzando el orden de "configuración", y eso requiere más lectura de código de un desarrollador para saberlo. Luego, cuando vaya a hacer un método como$employee->promote($newPosition);
, debe verificar una marca para ver si se realizó la validación o asumir que no se ha hecho y volver a hacerlo (redundante).$employee->updateWorkStatus($hired, $hireDate);
o si más avanzado$employee->adminUpdate(\Employee\AdminUpdateDTO $dto);
. Ahora puede validar en el contexto que necesita y decidir si se necesita alguna validación adicional.Este post no es específicamente sobre
__get
y__set
sino__call
que es la misma idea, excepto para llamadas de método. Como regla general, me mantengo alejado de cualquier tipo de método mágico que permita la sobrecarga por las razones descritas en los comentarios y publicaciones SIN EMBARGO , recientemente me encontré con una API de terceros que uso que utiliza un SERVICIO y un SUBSERVICIO, por ejemplo :La parte importante de esto es que esta API tiene todo lo mismo excepto la sub-acción, en este caso
doActionOne
. La idea es que el desarrollador (yo y otras personas que usen esta clase) podría llamar al subservicio por su nombre en lugar de algo como:Podría hacer en su lugar:
Para codificar no sería más que una gran cantidad de duplicación (este ejemplo esta muy asemeja vagamente el código):
Pero con el método mágico de
__call()
puedo acceder a todos los servicios con métodos dinámicos: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 a la clase o crear una clase extendida, etc. No estoy seguro de si esto es útil para nadie, pero pensé que podría mostrar un ejemplo donde
__set
,__get
,__call
, etc. puede ser una opción para su consideración 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 escenario. No es la API a la que me refería, pero la aplicación de los métodos es idéntica:
¿Estoy usando la API correctamente?
fuente
Actualización: No use esta respuesta ya que este es un código muy tonto que encontré mientras aprendía. Simplemente use getter y setter simples, es mucho mejor.
Por lo general, uso ese nombre de variable como nombre de función, y agrego un parámetro opcional a esa función para que cuando el llamante complete ese parámetro opcional, luego lo establezca en la propiedad y devuelva $ este objeto (encadenamiento) y luego cuando ese parámetro opcional no se especifica por persona que llama, acabo de devolver la propiedad a la persona que llama.
Mi ejemplo:
fuente