Должен ли я использовать assert в моем коде PHP? - PullRequest
83 голосов
/ 23 декабря 2010

Сотрудник несколько раз добавил команду assert в наших библиотеках в тех местах, где я бы использовал оператор if и выдал исключение. (До этого я даже не слышал об утверждении.) Вот пример того, как он использовал это:

assert('isset($this->records); /* Records must be set before this is called. */');

Я бы сделал:

if (!isset($this->records)) {
    throw new Exception('Records must be set before this is called');
}

Из чтения документации PHP по assert похоже, что рекомендуется убедиться, что assert активен, и добавить обработчик перед использованием assert. Я не могу найти место, где он это сделал.

Итак, мой вопрос, является ли использование assert хорошей идеей, учитывая вышеизложенное, и должен ли я использовать ее чаще, чем if и исключения?

Еще одно замечание: мы планируем использовать эти библиотеки на различных проектах и ​​серверах, включая проекты, в которые мы даже не можем участвовать (библиотеки с открытым исходным кодом). Имеет ли это какое-то значение при использовании assert?

Ответы [ 8 ]

77 голосов
/ 23 декабря 2010

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

В этом случае я бы сказал, что assert является подходящим (исходя из моего слабого понимания ситуации), потому что records должен всегда быть установлен до вызова данного метода. Таким образом, невозможность установить запись была бы ошибкой в ​​программе, а не условием времени выполнения. Здесь assert помогает обеспечить (при адекватном тестировании) отсутствие возможного пути выполнения программы, который мог бы вызвать код, защищаемый с помощью assert, без вызова records.

Преимущество использования assert по сравнению с if состоит в том, что assert обычно можно отключить в производственном коде, что снижает накладные расходы. Ситуации, которые лучше всего обрабатываются с помощью if, могут, по-видимому, происходить во время выполнения в производственной системе, и поэтому ничего не теряется, если они не могут их отключить.

24 голосов
/ 30 августа 2013

Думайте об утверждениях как о «силовых комментариях». Вместо комментария вроде:

// Note to developers: the parameter "a" should always be a number!!!

использование:

assert('is_numeric(a) /* The parameter "a" should always be a number. */');

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

С этой точки зрения утверждения - это совершенно другое понятие, чем if (ошибка) ... и исключения, и они могут сосуществовать.

Да, вы должны комментировать свой код, и да, вы должны использовать «мощные комментарии» (утверждения), когда это возможно.

15 голосов
/ 23 декабря 2010

Это полностью зависит от вашей стратегии развития.Большинство разработчиков не знают о assert() и используют последующее модульное тестирование.Но превентивные и встроенные схемы тестирования иногда могут быть выгодными.

assert полезно, потому что его можно включать и отключать.Это не снижает производительность, если такой обработчик утверждений не определен.У вашего коллеги его нет, и вы должны разработать некоторый код, который временно включает его в среде разработки (если включены E_NOTICE / E_WARNING, поэтому должен быть обработчик утверждений).Я использую его иногда, когда мой код не может справиться со смешанными типами переменных - я обычно не занимаюсь строгой типизацией в слабо типизированном PHP, но есть случайные случаи использования:

 function xyz($a, $b) {
     assert(is_string($a));
     assert(is_array($b));

, которые, например, компенсируютза отсутствием спецификаторов типа string $a, array $b.PHP5.4 будет их поддерживать, но не проверять.

7 голосов
/ 23 декабря 2010

Assert не заменяет нормальное управление потоком, такое как if или исключения, потому что оно предназначено только для отладки во время разработки.

5 голосов
/ 29 июня 2015

Важное замечание относительно assert в PHP ранее, чем 7. В отличие от других языков с конструкцией assert, PHP не выбрасывает операторы assert полностью - он обрабатывает их как функцию (делает debug_backtrace () в функции, вызываемойутверждение).Выключение утверждений, кажется, просто связывает функцию с тем, чтобы ничего не делать в двигателе.Обратите внимание, что PHP 7 может быть создан для эмуляции этого поведения, установив для zend.assertions значение 0 вместо более обычных значений 1 (вкл) или -1 (выкл).

Проблема возникает в том, что assert будет приниматьлюбой аргумент - но если аргумент не является строкой, тогда assert получает результаты выражения, независимо от того, включено или выключено assert.Вы можете проверить это с помощью следующего блока кода:

<?php
  function foo($a) { 
    echo $a . "\n"; 
    return TRUE;
  }
  assert_options(ASSERT_ACTIVE, FALSE);

  assert( foo('You will see me.'));
  assert('foo(\'You will not see me.\')');

  assert_options(ASSERT_ACTIVE, TRUE);

  assert( foo('Now you will see'));
  assert('foo(\'both of us.\')');

Учитывая намерение assert, это ошибка, и она давно существует, поскольку она существует в языке с тех пор, как assert была введена еще в PHP 4.

Строки, передаваемые в assert, оцениваются, со всеми вытекающими отсюда последствиями и опасностями для производительности, но это единственный способ заставить операторы assert работать так, как они должны работать в PHP (Такое поведение устарело в PHP7.2).

РЕДАКТИРОВАТЬ: Изменено выше, чтобы отметить изменения в PHP 7 и 7.2

4 голосов
/ 23 декабря 2010

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

3 голосов
/ 07 декабря 2018

Нет, ваш коллега не должен использовать его как обработчик ошибок общего назначения.Согласно инструкции:

Утверждения следует использовать только как функцию отладки.Вы можете использовать их для проверок работоспособности, которые проверяют условия, которые всегда должны быть ИСТИНА, и которые указывают на некоторые ошибки программирования, если нет, или для проверки наличия определенных функций, таких как функции расширения или определенные системные ограничения и функции.

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

Если вы знакомы с автоматизированными наборами тестов, обычно используется глагол "assert" для проверкивывод какого-либо метода или функции.Например:

function add($a, $b) {
    return $a + $b;
}

assert(add(2,2) == 5, 'Two and two is four, dummy!');
assert(is_numeric(add(2,2)), 'Output of this function to only return numeric values.');

Ваш коллега не должен использовать его в качестве обработчика ошибок общего назначения и в этом случае в качестве проверки ввода.Похоже, что поле записей не может быть установлено каким-либо пользователем вашей библиотеки.

3 голосов
/ 27 декабря 2015

Ваш коллега действительно пытается применить Design-by-Contract (TM) на языке Eiffel, основываясь на книге «Создание объектно-ориентированного программного обеспечения, 2-е издание».

Утверждение, которое он использовал, было бы{P} -часть логики Хоара или тройки Хоара: {P} C {Q}, где {P} - это утверждение предварительного условия (ion) s, а {Q} - это утверждение после условия (ion) s.

Я бы критически принял к сведению советы о том, что функция assert в PHP имеет ошибки.Вы не хотите использовать глючный код.Что вам действительно нужно, так это создателям PHP исправить ошибку в assert.Пока они этого не сделают, вы можете использовать assert, но используйте его, помня о его текущем состоянии ошибки.

Более того, если функция assert содержит ошибки, то я предлагаю вам не использовать ее в рабочем коде.Тем не менее, я рекомендую использовать его при разработке и тестировании кода, где это уместно.

Наконец, если вы изучите проектирование по контракту, вы обнаружите, что использование булевых утверждений в свете имеет последствияобъектно-ориентированного классического наследования - то есть - вы никогда не должны ослаблять предварительное условие или ослаблять постусловие.Это может быть опасно для взаимодействующих друг с другом полиморфных потомков.Пока вы не поймете, что это значит - я бы оставил это в покое!

Более того - я настоятельно рекомендую разработчикам PHP всесторонне изучить проектирование по контракту и попытаться включить его в PHP как можно скорее!Тогда всем нам может быть полезен компилятор / интерпретатор с поддержкой DbC, который бы решал проблемы, отмеченные в ответах (выше):

  1. Правильно реализованный компилятор с поддержкой проектирования по контракту будет(надеюсь) не будет ошибок (в отличие от текущего утверждения PHP).
  2. Правильно реализованный компилятор с поддержкой Design-by-Contract будет обрабатывать нюансы управления логикой полиморфного утверждения вместо того, чтобы ломать голову надВопрос!

ПРИМЕЧАНИЕ. Даже использование оператора if в качестве замены утверждения (предусловия) будет иметь тяжелые последствия, если его использовать для усиления предусловия или ослабления постусловия.Чтобы понять, что это значит, вам нужно изучить Design-by-Contract, чтобы знать!: -)

Счастливого обучения и учебы.

...