Чрезмерное использование строковых констант PHP?

У меня есть два конкретных случая, когда я не согласен с коллегой по поводу того, следует ли использовать константы или нет.

Мы используем самодельный фреймворк, работающий примерно как Symfony 1.x.

  1. Исходный код был в конфигурационном файле маршрутизации PHP для маршрутизации, например:

    $router->map('/some_url', array('module' => 'some_module', 'action' => 'some_action'));
    $router->map('/some_other_url', array('module' => 'some_module', 'action' => 'some_action'));
    // etc.
    

    Сотрудник изменил его на:

    $router->map('/some_url', array(MODULE => 'some_module', ACTION => 'some_action'));
    $router->map('/some_other_url', array(MODULE => 'some_module', ACTION => 'some_action'));
    
    // + in constants.php file:
    define('MODULE', 'module');
    define('ACTION', 'action');
    

    IMO, это постоянное чрезмерное использование: если понятие «модуль» или «действие» когда-либо будет переименовано, его придется переименовать во всем коде, будь то в виде строки или константы. Кроме того, указанные выше имена констант не имеют конкретного значения, что способствует коллизиям/путаницам в именах.

  2. Пример исходного кода:

    if (isset($_SESSION['unid']) && isset($_SESSION['login'])) { ... }
    

    Изменено коллегой:

    if (isset($_SESSION[UNID]) && isset($_SESSION[LOGIN])) { ... }
    
    // + in a constants.php file:
    define('UNID', 'unid');
    define('LOGIN', 'login');
    

    В нашем приложении имена этих сеансовых переменных unid и login вряд ли изменятся. Тем не менее, если бы объявление констант было действительно хорошей практикой, я бы предложил хотя бы более точные имена, например FIELDNAME_UNID и FIELDNAME_LOGIN...

Является ли введение этих констант действительно актуальным (то есть, именование должно быть просто улучшено) или (как я предполагаю) совершенно бесполезным?

Спасибо.

ИЗМЕНИТЬ

Спустя несколько месяцев вот несколько (невероятных) строк из файла constants.php. Я определенно нахожу это совершенно бесполезным беспорядком, похожим на эту публикацию DailyWTF. Слишком много констант убивает константы.

define('POST', 'POST');
define('GET', 'GET');

define('PROJECT', 'project');
define('APPLICATION', 'application');
define('MODULE', 'module');
define('ACTION', 'action');
define('ID', 'id');
define('SLUG', 'slug');
define('CONTROLLER', 'controller');
define('CONTENT', 'content');
define('AJAX', 'ajax');
define('EXECUTE', 'execute');
define('FORMAT', 'format');
define('BASE_HREF_CONSTANT', 'basehref');
define('UNID', 'unid');
define('USERNAME', 'username');
define('PASSWORD', 'password');
define('TEMPLATE', 'templates');
define('UNSECURE', 'unsecure');
define('MODE', 'mode');
define('MESSAGE', 'message');
define('TEMPORARY_SESSION', 'temporary_session');
define('ERRORMESSAGE', 'errormessage');
define('START_FROM', 'startfrom');
define('COUNT', 'count');

// and so on.

person Frosty Z    schedule 28.06.2011    source источник
comment
Связано: заголовок stackoverflow.com/questions/4234129/   -  person Frosty Z    schedule 29.06.2011
comment
Не совсем связано (касается жестко закодированных чисел), но стоит прочитать: stackoverflow.com/questions/47882/   -  person James P.    schedule 29.06.2011
comment
разве это не всегда заканчивается личным предпочтением.   -  person    schedule 29.06.2011
comment
Да, но иногда это приводит к плохому дизайну. Ниже я сказал о личных предпочтениях, потому что в этих случаях выбор любого из двух вариантов не кажется очевидной плохой практикой.   -  person Frosty Z    schedule 29.06.2011


Ответы (3)


Существует веский аргумент в пользу использования таких констант.

Если вы случайно сделаете что-то вроде:

$router->map('/some_url', array('moduel' => 'some_module', 'action' => 'some_action'));

он потерпит неудачу каким-то неопределенным образом (обратите внимание на неправильное написание «moduel»).

Если вы сделаете орфографическую ошибку или опечатку, когда речь идет о константе, PHP выдаст уведомление, и вы сразу же его поймаете.

Как часто это на самом деле спасает вас, является предметом споров. Лично я обычно не думаю, что это стоит хлопот.

person timdev    schedule 28.06.2011
comment
Это аргумент. Однако в этом случае метод map() должен проверять необходимые данные, и в этом случае он будет жаловаться на отсутствующую информацию о «модуле». - person Frosty Z; 29.06.2011
comment
Кроме того (даже если это маловероятно), если ваша орфографическая ошибка заканчивается уже определенной константой other, уведомление PHP не будет отображаться :) - person Frosty Z; 29.06.2011
comment
@FrostyZ - я почти сказал что-то подобное, но передумал. В этом конкретном примере вполне вероятно, что map() по умолчанию будет использовать любой текущий модуль, в отсутствие параметра с ключом «модуль». Это может потерпеть неудачу совершенно бесшумно. - person timdev; 29.06.2011
comment
@FrontyZ - Что касается вашего второго комментария, да, тогда вы полностью вернулись к исходной точке. Как я уже сказал в своем ответе, кажется, не стоит заморачиваться. - person timdev; 29.06.2011
comment
Через несколько месяцев, перечитывая это снова... Отвечая timdev на три комментария выше: я могу утверждать, что проверка параметров может просто проверять список поддерживаемых параметров (обязательных/необязательных). Затем, в случае ошибки при вводе типа 'moduel', разработчику может быть показано какое-то сообщение (поскольку это имя параметра не входит в число поддерживаемых параметров функции). - person Frosty Z; 30.09.2011

Преимущества

  • последствия неправильного написания константы должны вызывать E_NOTICE 'Использование неопределенной константы', тогда как неправильное написание строкового литерала не дает такого раннего предупреждения.
  • если следовать до логического завершения, любые оставшиеся строковые литералы в коде должны быть на естественном языке, и, таким образом, задача идентификации строк, которые должны быть заключены в слой перевода интернационализации, становится немного проще.

Недостатки

  • требует, чтобы вы определили все константы, нужны они вам или нет. Однако вряд ли это будет вашим узким местом в производительности, если вы не определите тысячи из них!
person Paul Dixon    schedule 28.06.2011

И главная причина, конечно же, в автодополнении IDE.
При использовании констант вам даже не нужно будет писать полное имя константы (в этом вам поможет IDE), и вы будете абсолютно уверены, что у вас нет опечаток.

Это не злоупотребление. Например, я стараюсь избегать использования строк в коде.

person OZ_    schedule 29.06.2011
comment
Автодополнение — это аргумент. Однако: либо вы загромождаете свое глобальное пространство имен нечеткими именами констант, выполняя множество define('CONSTANT', 'constant');, то автодополнение может быть контрпродуктивным (может предлагать много значений + неправильные значения среди предложений + вы не можете быть на 100% уверены, что при орфографической ошибке результирующая константа имя не уже определено + проблема коллизии имен...). Либо вы правильно называете свои константы, например Router::CODE_ACTION или ModelUser::FIELD_LOGIN, и было бы интересно точно сравнить читабельность, быстроту ввода, предотвращение ошибок и т. д. - person Frosty Z; 29.06.2011
comment
... избегать магических чисел и магических строк, безусловно, хорошо, но, как и в любом правиле, могут быть исключения. - person Frosty Z; 29.06.2011
comment
@Frosty Z, сейчас я не использую глобальные константы, только константы класса. И да, конечно должны быть исключения из этого правила, иначе код получится слишком длинным :) - person OZ_; 29.06.2011