Плюсы и минусы интерфейсных констант

Интерфейсы PHP позволяют определять константы в интерфейсе, например

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

Любой класс реализации автоматически будет иметь эти константы, например

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

Мое собственное мнение об этом заключается в том, что все Глобальное злом . Но мне интересно, что же касается интерфейсных констант. Учитывая, что кодирование с интерфейсом считается хорошей практикой в ​​целом, использует константы интерфейса только константы, приемлемые для использования вне контекста класса?

Хотя мне любопытно услышать ваше личное мнение и используете ли вы интерфейсные константы или нет, я в основном искал объективные причины в ваших ответах. Я не хочу, чтобы это был вопрос типа опроса. Меня интересует, какое влияние имеет использование констант интерфейса для обеспечения работоспособности. Связь. Или модульное тестирование. Как это связано с SOLID PHP? Нарушает ли он какие-либо принципы кодирования, которые считаются надлежащей практикой в ​​PHP? Вы получаете идею …

Примечание: для Java существует аналогичный вопрос, в котором перечислены некоторые довольно веские причины, по которым они являются плохой практикой, но поскольку Java не является PHP, я счел оправданным повторить его в теге PHP.

Related of "Плюсы и минусы интерфейсных констант"

Ну, я думаю, что это сводится к разнице между хорошим и достаточно хорошим .

Хотя в большинстве случаев вы можете избежать использования констант, реализуя другие шаблоны (стратегию или, возможно, мухи), есть что сказать, потому что вам не понадобится полдюжины других классов для представления концепции. Я думаю, что это сводится к тому, насколько вероятна потребность в других константах. Другими словами, существует ли необходимость в расширении ENUM, обеспечиваемого константами интерфейса. Если вы можете предвидеть необходимость его расширения, перейдите к более формальному шаблону. Если нет, то этого может быть достаточно (это будет достаточно хорошо, и, следовательно, будет меньше кода для записи и тестирования). Вот пример достаточно хорошего и плохого использования:

Плохо:

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

Достаточно хорошо:

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

Теперь причина, по которой я выбрала эти примеры, проста. User интерфейс определяет перечисление типов пользователей. Это, скорее всего, будет расширяться с течением времени и будет лучше соответствовать другому шаблону. Но HTTPRequest_1_1 является достойным вариантом использования, поскольку перечисление определено RFC2616 и не изменится на время жизни класса.

В общем, я не вижу проблемы с константами и константами класса как глобальной проблемой. Я рассматриваю это как проблему зависимости. Это узкое различие, но определенное. Я вижу глобальные проблемы, как в глобальных переменных, которые не применяются, и как таковые создают мягкую глобальную зависимость. Но класс с жестким кодированием создает принудительную зависимость и, таким образом, создает жесткую глобальную зависимость. Таким образом, оба являются зависимостями. Но я считаю, что глобальное положение будет намного хуже, поскольку оно не применяется … Вот почему я не люблю группировать зависимости классов с глобальными зависимостями под одним и тем же баннером …

Если вы пишете MyClass::FOO , вы жестко привязаны к деталям реализации MyClass . Это создает жесткую связь, что делает ваш код менее гибким и как такового следует избегать. Однако существуют интерфейсы, позволяющие именно такой тип связи. Поэтому MyInterface::FOO не вводит никакой конкретной связи. С учетом сказанного я бы не вводил интерфейс, чтобы добавить к нему константу.

Поэтому, если вы используете интерфейсы, и вы очень уверены, что вам (или кому-то еще в этом случае) не понадобятся дополнительные значения, то я действительно не вижу огромной проблемы с константами интерфейса … Лучшее конструкции не включали бы никаких констант или условностей или магических чисел или магических нитей или жестко закодированных вещей. Однако это добавляет дополнительное время для разработки, так как вы должны учитывать использование. Я считаю, что в большинстве случаев стоит потратить дополнительное время на создание отличного прочного дизайна. Но бывают случаи, когда на самом деле достаточно приемлемо (и для понимания разницы требуется опытный разработчик), и в этих случаях это нормально.

Опять же, это только мой взгляд на это …

Я думаю, что его обычно лучше обрабатывать константы, специально перечисленные константы, как отдельный тип («класс») из вашего интерфейса:

 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) { ... } } 

или, если вы хотите использовать класс в качестве пространства имен:

 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) { ... } } 

Не то, что вы используете только константы, вы используете концепцию перечисляемых значений или перечислений, которые представляют собой набор ограниченных значений, считаются конкретным типом с конкретным использованием («домен»?)