Pull to refresh

Comments 73

Да по-моему лучше пользоваться empty(), чем создавать функцию.
А вообще, кому как удобней.
chk одновременно проверяет на наличие и возвращает элемент. Конечно, функция не для определенных ситуаций.
да, в мануале php в комментах именно так, как вы и указали. Но проблема в том, что в этом случае индекс создастся, если его нет в массиве.
не создастся, ей-богу.
я даже не поленился проверить, чтобы уличить вас во лжи!
Сорри, я совсем не собирался врать :(

Спутал с похожей функцией, которую предлагали в комментах мануала php:

Beware that the chk() function below creates the variable or the array index if it didn't existed.
<?php
function chk(&$var) {
if (!isset($var))
return NULL;
else
return $var;
}

Вот так создается индекс:

chk($a['b']);
UFO landed and left these words here
В большинстве случаев необходимо по дефолту ставить какое-то значение. Поэтому как минимум в Вашу функцию я бы добавил третий параметр (как раз дефолтное значение).
Ага, а если его поставить перед include, то вообще все подавляет в подключенном файле.
Всё-таки собаки чаще зло. display_erros=off и дело с концом. Логи очень часто помагают отловить неожиданные ошибки.

Сам использую собак только в @mysql_connect/@mysql_select_db.
Оператор @ - быстрое решение, когда лень писать много кода. Но предыдущее предложение _не_ означает, что @ - зло. Зло всегда происходит от неправильного ее применения. Конечно, в законченных скриптах не рекомендуется применять.

Есть четкие правила использования оператора @:
* общее - только перед встроенными функциями:
$f = @fopen($fname);
$d = @mysql_connect(...);
@mkdir(...)

* при проверке возможно неинициализированных переменных: if(@$_POST['var'])

* Когда лень писать много кавычек в массивах: @$arr[element1][element2][element3]

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

Ни в коем случае нельзя использовать оператор @ перед:
* директивой include(), так как подавятся все сообщения об ошибках во включаемом файле.
* перед вызовом собственных функций.
* перед функцией eval()

Замечу также, что оператор @ лишь подавляет вывод сообщений об ошибках в браузер. В логи сообщения будут продолжать писаться (при включенном log_error, конечно же)
@$arr[element1][element2][element3].
Собака, ради того, чтобы не ставить кавычки — по-моему уже перебор.
define('element1',777); и становится очень грустно)
Еще @ ни в коем случае нельзя использовать в циклах, так как работает она так: выставляется error_reporting в 0, вызывается Ваша ф-ция, выставляется error_reporting в старое значение. Так что если цикл длинный, то @ может существенно повлиять на скорость его прохождения.
Видел я один раз код такого ленивого програмера. Что еще хуже я сидел и около 2-х часов пытался найти в чем же там проблема, почему ничего не работает через раз и почему мне об этом ничего даже не сообщаеца. Проблема решилась за две минуты, как только я убрал собаку из вызова одной функции.

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

А про забитие на кавычки в массивах и isset при проверке входящих данных(который вообще пишется только один раз и помещается в какой-нибудь компонент работаютщий) - за это, извините, но надо избивать. Причем до тех пор, пока человек не поймет, что если он будет писать номральный грамотный и читаемый код, который сам ему подскажет что к чему - то он так и будет тратить 80% своего времени заниямась рутинным кодингом.
Конечно, отчасти вы правы.
Но не стоит, однако, путать лень хорошего программиста, с нежеланием быдлокодера писать хороший код. Первый знает что и почему он делает; второй делает, чтобы "замазать", спрятать надоедающие вещи, не понимая причины их появления и нежелая их исправлять.

Вся тонкость оператора @ как раз состоит в том, что при и только при правильном его применении он позволяет написать короткий и элегантный код.

Однако, опять же, обращаю ваше внимание на то, что использование оператора @ в _законченных_ скриптах не рекомендуется - лучше применять его только при отладке.
Приведите пожалуйста пример короткого элегантного кода с использованием собаки. Просто я, к сожелению не могу себе представить такой ситуации.
if(@$_POST['varname']){
}

вместо

if(isset($_POST['varname'])){
}
Да, конечно, будьте так любезны.
Можно начать с того, что все таки в данном случае мы проверяем есть ли у нас такая переменная, или нет. isset логически подходит сюда гораздо больше.

И продолжить тем, что обращатся напрямую к посту, в нормальном приложении - дурной тон, как уже было сказанно выше (с приведенными примерами), лучше написать функцию\класс для работы с енвиронментом. Вопервых, мы избавим себя от рутинного кода в будущем, во вторым - сократим количество потенциальных дыр и улучшим читабельность.

В треитьих, посудите сами как будет выглядить такой код, если нам нужно будет вытащить несколько переменных из поста\гета?
Эти два блока кода будут работать по-разному, если, например, $_POST['varname'] = 0.
То есть, первое условие вернет false, а второе - true.
Это основная проблема.
if(!$id = intval(@$_GET['id'])) мне нравится больше чем тоже самое через isset
Поздравляю, более ужасного когда я еще
сегодня не видел
Увы, забывать нельзя. В некоторых случаях без @ невозможно обойтись, например, если используете функции, которые в некоторых случаях могут неконтролируемо бросать warnings. Например, как говорили ниже, @mail().
Увы, это глобально выключит вывод warnings. а если нужно, чтобы они были, но не везде? Например, если занимаетесь отладкой какого-либо нового модуля, и включили для этого display_errors, зачем же засорять вывод еще и сообщениями из других, уже давно отлаженных и стабильно работающих модулей.
Если для отладки, тогда вы правы, еще можно, но продакшн-коде собак надо избегать, они пагубно сказываются на производительности. Я имел в виду именно продакшн.
а можно привести пример параметров для mail(), когда он неконтролируемо бросит warning, который ничо вообщем-то и не значит?
Warning возможен при любых параметрах mail(), даже абсолютно корректных. Тут же многое зависит не только от параметров, но и от настроек SMTP сервера и от окружения, а также от того, есть ли возможность отправлять письма заданным способом по заданному адресу. Чаще чаще всего бывает что-то типа:

Warning: mail() [function.mail]: SMTP server response:… (тут код и описание ошибки, их бывает довольно много, например Invalid Address, Unable to relay for xxx@xxx.xx, и т.д.)
Хм, просто чесна говоря, когда я пользовался этой функцией у меня ворнинги возникали только в действительно неочень хороших ситуевинах, к примеру неправильное мыло…
UFO landed and left these words here
я написал быстрее :)
function getRequestParameter($key, $default = null)
{
if(isset($_REQUEST[$key])) return $_REQUEST[$key];
else return $default;
}
п.с.: возможны опечатки, т.к. писал прямо здесь.
можно модифицировать, чтобы брать значения только из гет, или только из пост, а не всего реквеста
Что-то вроде того, но я говорил о немного другом уровне, например таком:
class Request {
&nbspl&nbsplpublic function getQueryParam($name, Filter $filter, $default = null) {
&nbspl&nbspl&nbspl&nbsplif(isset($_GET[$name])) {
&nbspl&nbspl&nbspl&nbspl&nbspl&nbsplreturn ($filter)? $filter->apply($name) : $_GET[$name];
&nbspl&nbspl&nbspl&nbspl}
&nbspl&nbspl&nbspl&nbsplelse {
&nbspl&nbspl&nbspl&nbspl&nbspl&nbsplreturn $default;
&nbspl&nbspl&nbspl&nbspl}&nbspl&nbspl&nbspl
&nbspl&nbspl}

&nbspl&nbspl//...
}

Фильтры кстати тоже пишутся за час-два до приемлимого уровня ;)
Вы забыли ; после &nbsp :)

Ну а вообще стоит написать функцию типа getGET, которой третим параметром нужно подать еще и тип ожидаемого значения. А внутри уже распарсить.
Если потратить побольше времени и не полениться хорошо написать, функция вполне себе подойдет для копи-пастов в следующих проектах.
Не забыл, просто опечатался ;)

Вот как раз в этом куске кода, что бросил сюда из своего прожекта, этот параметр вообщем-то не и нужен - все это длается именно в фильтре(у меня куча различных фильтров на каждый тип данных со своими фишками ), по нему уже определяем какой типа нам нужен, и если к примеру нам нужен инт или флоат, а получаем строку, то можем выкинуть и UnexpectedValueException, если захотим. Или постараемся преобразовать ;)
Самое главное - @ не избавляет от ошибки, а только скрывает вывод.
Единственное, где можно использовать - исключительные случаи при чтении потоков на IIS, и некоторые другие.
C недавних пор я использую PHP5 и, соответственно, полностью отказался от экранирования ошибок.
Вот мое решение:

Файл MyException.class.php:


class MyException extends Exception {
public function __construct($message, $errorCode = 0, $errorFile = '', $errorLine = 0) {
parent::__construct($message, $errorCode);
$this->file = $errorFile;
$this->line = $errorLine;
}
}
set_error_handler(create_function('$c, $m, $f, $l', 'throw new MyException($m, $c, $f, $l);'), E_ALL);
?>


Далее в коде пишем так:

try {
$a = 57 / 0;
}
catch (Exception $e) {
echo $e;
}


Пояснения по коду:
По умолчанию, в 5-м PHP ошибки и исключения - это разные вещи, что странно. Поэтому просто ошибка при вызове функции исключения не вызовет.
А можно вопросек небольшой, зачем создавать лямбда функцию, если можно кинуть нормальный call-back?

Да и смысл всего этого действа, ведь на E_ALL, эксепшн вылезет даже там, где будет кинут простой notice.

И кстати. Ошибки и исключения - это разные механизмы.
  1. А кто мешает использовать нормальный call-back? Мне нравятся лямбда-функции, но вы можете использовать то, что вам удобнее
  2. Кто мешает вместо E_ALL поставить любую комбинацию уровней error reporting допустимых в error_reporting()? Не нравится notices? Используем в коде E_ALL & ~E_NOTICE!
  3. Читайте внимательно мои пояснения к моему же коду :)

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


lambda-функции сейчас, может, неэффективны в силу некоторых особенностей, но в предверии выхода PHP 5.3 уже можно потихоньку на них переходить, поскольку в этом релизе ситуация изменится кардинально!


И еще одно насчет notices: The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called. Так что не волнуйтесь, E_NOTICE в исключение не передается.


Подробнее о lambda-функциях
Про лямду в курсе, только вот пока до нее еще очень далеко. PHP 5.3 - это вообще другой язык, и неймспейсы, замыкания, может быть даже нормальный тайп хинтинг, traits... Но это все реально, к сожелению, очень далеко :(

Скопировал ваш код, запустил:
try {
$_POST['b'];
}
catch (Exception $e) {
echo $e;
}

Получил, как и ожидал: exception 'MyException' with message 'Undefined index: b' in D:\Web\home\localhost\htdocs\dev\Nano\index.php:45 Stack trace: #0 D:\Web\home\localhost\htdocs\dev\Nano\index.php(45): __lambda_func(8, 'Undefined index...', 'D:\Web\home\loc...', 45, Array) #1 {main}

Правда у меня нотисы я все таки выкинул, с помощью switch($errno), на E_NOTICE... так спокойнее.
Ну так а что не нравится?
Что exception вывело на экран? Так там echo стоит... Обрабатывайте как хотите.

Если вы по поводу того, что WARNING выкинул Exception, то опять же, отключите E_WARNING в set_error_handler.
То, что мне выкинулся эксепшн на обычный нотис. $_POST['b'] - в котором нет индекса b - это нотис, гласящий "Undefined index: b".
Еще в первом посте указал, как это обойти!
Вот только что проверил - работает:

set_error_handler(create_function('$c, $m, $f, $l', 'throw new MyException($m, $c, $f, $l);'), E_ALL & ~E_NOTICE);
Уф! Вам не угодишь :)
Во-первых, зачем красиво оформлять notice, если он предназначен только для разработчика? Во-вторых, а как бы вы красиво оформляли notice, не используя Exceptions - только стандартными функциями PHP?

Второй параметр в callback-функции ($errorCode) - это на самом деле:
the level of the error raised, as an integer


Так что переопределяйте метод __toString и вперед, за орденами:

public function __toString() {
if ($this->code === E_NOTICE) {
echo "Это красивый notice!!!";
}
}
Угу, придираюсь ;)

Я бы правда вынес нотис за грани эксепшна и проверял, что это нотис на уровне call-back-а (как вариант кидать NoticeException ;) ) и как-нибудь его выводил, хоть одной строкой, тут уже все равно.
Вот видите! Сообща нашли решение, которое более или менее устраивает обоих.
Выводить notice прямо в callback - наиболее приемлемое, на мой взгляд, решение. Оно позволяет в случае обхода массива в цикле вывести все notices, а не только первый.

Теперь вы согласны, что исключения в PHP более прогрессивный инструмент нежели стандартные ошибки и его можно и нужно заменять?
Согласен :) И давно его использую ;)

На set_exception_handler(), что нибудь накинули?
Пока нет. В небольшом проекте пока обыкновенными try...catch обхожусь.
Для ZF буду, конечно, применять.
Вот эта собака (@) стоила мне много времени и нервов при разборе неработоспособности чужого сложного кода.

НИКОГДА не юзайте собаку, кроме случаев, когда без нее никак (например @mail()). @ просто скрывает сообщение об ошибке, но оно все равно генерируется. А значит, кроме всего еще и время тратится лишнее. За всякие @$v[s] и @$_GET['ddd'] надо убивать.
давным-давно ждал этого оператора :) имхо очень удобно
Не отключать error_reporting на работающем сайте — верный способ проверить своё мужество. Для этого существуют белые списки. Что касается собачки, ей очень даже удобно подавлять предупреждения, в случае, если маскируемая функция так или иначе возвращает результат.
Использование @ возлагает обязанности по обработке ошибки на самого программиста. И если он таковые не выполняет, то уже можно сомневаться в его адекватности. В любом случае, надо чётко понимать, что происходит при использовании собаки. И error_reporting выставлять в E_ALL, ну и, конечно, display_errors в On. Ошибкам надо глядеть в лицо:)
Никогда не выставляйте на production-сайте display_errors в on.
@ НИКОГДА себя не оправдывает, никак. Это признак нубоватости кодера :)
По-моему это опять идет изобретение велосипеда. Имхо, можно юзать готовые решения из того же ZF, либо если проект написан вобще без использования каких либо фреймворков - просто портировать под него данное решение. И никаких @
если не сложно, опишите подробнее, что за решения
ZF в стандартной поставке, как таковой - это обертка для стандартного SPL Exception Class. Поэтому для исключений я использую в проектах расширенную (очень похоже на пример Yeah) версию класса Zend_Exception, а что касается ошибок пользовательского уровня (здесь подразумеваю всевозможные ошибки валидации форм и т.п.) класс ErrorHandler (тоже не входит в стандартную комплектацию).
По сути он делит ошибки на три вида - debug, warning, error и выводит их по соответствующим правилам. Можно назвать это расширенным логгером с возможностью тонкой настройки вывода ошибок (либо на экран либо в лог файл).
хотя при наличии java-script профи, лучше все же переложить обязанности по валидации форм на него :)
тем не менее, забывать про серверную валидацию тоже нельзя.
Валидация — только на сервере. На клиенте это называется assistance.
Sign up to leave a comment.

Articles