Pros y contras de las constantes de interfaz [cerrado]


Las interfaces PHP permiten la definición de constantes en una interfaz, por ejemplo,

interface FooBar
{
    const FOO = 1;
    const BAR = 2;
}
echo FooBar::FOO; // 1

Cualquier clase implementadora tendrá automáticamente estas constantes disponibles, por ejemplo,

class MyFooBar implement FooBar
{
}
echo MyFooBar::FOO; // 1

Mi propia opinión sobre esto es que cualquier cosa Global es Mala. Pero me pregunto si lo mismo se aplica a las Constantes de la Interfaz. Dado que Codificar contra una Interfaz se considera una buena práctica en general, es usar Constantes de Interfaz las únicas constantes que son aceptables para usar fuera de una clase contexto?

Si bien tengo curiosidad por escuchar su opinión personal y si utiliza constantes de la interfaz o no, estoy buscando principalmente razones objetivas en sus respuestas. No quiero que esto sea una pregunta tipo Encuesta. Estoy interesado en qué efecto tiene el uso de constantes de interfaz en la capacidad de mantenimiento. Acoplamiento. O Pruebas Unitarias. ¿Cómo se relaciona con SOLID PHP? ¿Viola algún principio de codificación que se considere una Buena Práctica en PHP? Usted consigue la idea ...

Nota: hay una pregunta similar para Java que enumeró algunas razones bastante buenas por las que son una Mala Práctica, pero como Java no es PHP, sentí que estaba justificado preguntarlo dentro de la etiqueta PHP nuevamente.

Author: Community, 2011-03-18

2 answers

Bueno, creo que todo se reduce a la diferencia entre buena y suficientemente bueno.

Mientras que en la mayoría de los casos se puede evitar el uso de constantes mediante la implementación de otros patrones (estrategia o tal vez peso mosca), hay algo que decir para no necesitar una media docena de otras clases para representar un concepto. Creo que lo que se reduce a, es lo probable es que hay una necesidad de otras constantes. En otras palabras, ¿hay una necesidad de extender la ENUMERACIÓN proporcionada por las constantes en la interfaz. Si puede prever la necesidad de expandirlo, entonces vaya con un patrón más formal. Si no, entonces puede ser suficiente (será lo suficientemente bueno, y por lo tanto habrá menos código para escribir y probar). He aquí un ejemplo de un uso suficientemente bueno y un mal uso:

Malo:

interface User {
    const TYPE_ADMINISTRATOR = 1;
    const TYPE_USER          = 2;
    const TYPE_GUEST         = 3;
}

Suficientemente bueno:

interface HTTPRequest_1_1 {
    const TYPE_CONNECT = 'connect';
    const TYPE_DELETE  = 'delete';
    const TYPE_GET     = 'get';
    const TYPE_HEAD    = 'head';
    const TYPE_OPTIONS = 'options';
    const TYPE_POST    = 'post';
    const TYPE_PUT     = 'put';

    public function getType();
}

Ahora, la razón por la que elegí esos ejemplos es simple. La interfaz User está definiendo una enumeración de tipos de usuario. Esto es muy probable que se amplíe con el tiempo y sería más adecuado por otro patrón. Pero el HTTPRequest_1_1 es un caso de uso decente, ya que la enumeración está definida por RFC2616 y no cambiará durante la vida útil de la clase.

En general, no veo el problema con las constantes y las constantes de clase como un problema global. Lo veo como un problema de dependencia. Es una distinción estrecha, pero definitiva. Veo problemas globales como en variables globales que no se aplican, y como tales crean una dependencia global suave. Pero una clase codificada crea una dependencia forzada, y como tal crea una dependencia global dura. Así que ambas son dependencias. Pero considero que el global es mucho peor ya que no se aplica... Por eso no me gusta agrupar dependencias de clase con dependencias globales bajo el mismo banner...

Si escribes MyClass::FOO, estás codificado con los detalles de implementación de MyClass. Esto crea un acoplamiento duro, lo que hace que su código sea menos flexible, y como tal debe evitarse. Sin embargo, existen interfaces que permiten exactamente este tipo de acoplamiento. Por lo tanto, MyInterface::FOO no introduce ningún acoplamiento de hormigón. Dicho esto, no introduciría una interfaz solo para agregar una constante a ella.

Así que si estás usando interfaces, y estás muy seguro de que tú (o cualquier otra persona para el caso) no necesitará valores adicionales, entonces realmente no veo un gran problema con las constantes de la interfaz... Los mejores diseños no incluirían constantes o condicionales o números mágicos o cuerdas mágicas o cualquier cosa codificada. Sin embargo, eso agrega tiempo adicional al desarrollo, ya que debe considerar los usos. Mi opinión es que la mayoría de las veces vale la pena tomarse el tiempo adicional para construir un gran diseño sólido. Pero hay momentos en que suficientemente bueno realmente es aceptable (y se necesita un desarrollador experimentado para entender la diferencia), y en esos casos está bien.

De nuevo, esa es solo mi opinión al respecto...

 119
Author: ircmaxell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-24 13:59:30

Creo que generalmente es mejor manejar constantes, constantes especialmente enumeradas, como un tipo separado ("clase") de su interfaz:

define(TYPE_CONNECT, 'connect');
define(TYPE_DELETE , 'delete');
define(TYPE_GET    , 'get');
define(TYPE_HEAD   , 'head');
define(TYPE_OPTIONS, 'options');
define(TYPE_POST   , 'post');
define(TYPE_PUT    , 'put');

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

O, si desea usar una clase como espacio de nombres:

class TypeHTTP_Enums
{
  const TYPE_CONNECT = 'connect';
  const TYPE_DELETE  = 'delete';
  const TYPE_GET     = 'get';
  const TYPE_HEAD    = 'head';
  const TYPE_OPTIONS = 'options';
  const TYPE_POST    = 'post';
  const TYPE_PUT     = 'put';
}

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

No es que esté utilizando solo constantes, está utilizando el concepto de valores enumerados o enumeraciones, que un conjunto de valores restringidos, se consideran un tipo específico, con un uso específico ("dominio" ? )

 10
Author: umlcat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-27 16:26:28