接口常量的优缺点

Gor*_*don 101 php interface constants

PHP接口允许在接口中定义常量,例如

interface FooBar
{
    const FOO = 1;
    const BAR = 2;
}
echo FooBar::FOO; // 1
Run Code Online (Sandbox Code Playgroud)

任何实现类都将自动提供这些常量,例如

class MyFooBar implement FooBar
{
}
echo MyFooBar::FOO; // 1
Run Code Online (Sandbox Code Playgroud)

我对此的看法是,任何Global都是邪恶的.但我想知道接口常量是否同样适用.鉴于对接口的编码通常被认为是良好的做法,使用接口常量是在类上下文之外使用的唯一常量吗?

虽然我很想听听您的个人意见以及您是否使用界面常量,但我主要是在您的答案中寻找客观原因.我不希望这是一个民意调查问题.我对使用接口常量对可维护性有什么影响感兴趣.耦合.或单元测试.它与SOLID PHP有什么关系?它是否违反了任何被认为是PHP良好实践的编码原则?你明白了......

注意: Java有一个类似的问题列出了一些很好的理由,说明它们是Bad Practice,但由于Java不是PHP,我认为再次在PHP标记中提出它是合理的.

irc*_*ell 133

好吧,我认为这归结为之间的差异.

虽然在大多数情况下你可以通过实现其他模式(策略或者可能是flyweight)来避免使用常量,但是有一些东西可以说是不需要其他六个类来表示一个概念.我认为它归结为,是否有可能需要其他常量.换句话说,是否需要扩展接口上常量提供的ENUM.如果您可以预见需要扩展它,那么请采用更正式的模式.如果没有,那么它就足够了(它足够好,因此编写和测试的代码更少).这是一个足够好和坏用途的例子:

坏:

interface User {
    const TYPE_ADMINISTRATOR = 1;
    const TYPE_USER          = 2;
    const TYPE_GUEST         = 3;
}
Run Code Online (Sandbox Code Playgroud)

够好了:

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();
}
Run Code Online (Sandbox Code Playgroud)

现在,我选择这些例子的原因很简单.所述User接口被限定的用户类型的枚举.这很可能随着时间的推移而扩大,并且更适合另一种模式.但是这HTTPRequest_1_1是一个不错的用例,因为枚举是由RFC2616定义的,并且在类的生命周期内不会改变.

一般来说,我没有看到常量和类常量作为全局问题的问题.我认为这是一个依赖问题.这是一个狭隘的区别,但是一个明确的区别.我将全局问题视为未强制执行的全局变量,并因此创建一个软全局依赖.但是,硬编码的类会创建强制依赖,因此会创建一个强大的全局依赖.所以两者都是依赖关系.但我认为全局变得更糟,因为它没有被强制执行......这就是为什么我不喜欢在同一个横幅下将类依赖性全局依赖关系混为一谈......

如果你写MyClass::FOO,你就会被硬编码为实现细节MyClass.这会产生硬耦合,这会使您的代码不够灵活,因此应该避免.但是,存在接口以允许这种类型的耦合.因此MyInterface::FOO不引入任何具体的耦合.话虽如此,我不介绍一个接口只是为了添加一个常量.

因此,如果你正在使用接口,并且你非常确定你(或其他任何人)不需要额外的值,那么我真的没有看到界面常量的巨大问题......最好的设计不包括任何常数或条件或魔术数字或魔术字符串或硬编码的任何东西.但是,这会增加开发时间,因为您必须考虑使用.我的观点是,大多数时候绝对值得花费额外的时间来构建一个坚固的设计.但有些时候确实可以接受足够好(并且需要经验丰富的开发人员理解其中的差异),在这些情况下它很好.

再一次,这只是我对它的看法......

  • 在这种情况下,您会建议用户使用不同的模式? (4认同)
  • 非常扎实和清晰的答案!+1 (3认同)
  • @FrederikKrautwald:你可以避免多态的条件(在大多数情况下):检查[这个答案](http://stackoverflow.com/a/7264192/338665)以及[看这个清洁代码谈话](http:/ /www.youtube.com/watch?v=4F72VULWFvc)... (2认同)

uml*_*cat 10

我认为通常更好地处理常量,特别是枚举常量,作为一个单独的类型("类")从您的接口:

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) { ... }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果要将类用作命名空间:

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) { ... }
}
Run Code Online (Sandbox Code Playgroud)

它不是你只使用常量,而是使用枚举值或枚举的概念,其中一组受限值被视为特定类型,具有特定用法("域"?)