Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

PHP5_nachinayushim

.pdf
Скачиваний:
29
Добавлен:
20.03.2015
Размер:
26.79 Mб
Скачать

224Глава 5

log_errors: инструктирует PHP регистрировать ошибки в журнале. Как и в слу+ чае других систем протоколирования ошибок, можно определить количество аккумулируемых в журнале сообщений об ошибках.

track_errors: включение этого параметра позволяет в любом сценарии полу+ чить самое последнее сообщение об ошибке (если она произошла) из постоян+ но доступной встроенной переменной $php_errmsg. Эта переменная не явля+ ется суперглобальной; она доступна только в пределах той области видимости, в которой произошла ошибка.

Типы ошибок в PHP

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

Критическая (или неисправимая) ошибка (Fatal Error): полностью прекращает выполнение сценария. Существуют критические ошибки времени выполнения, времени компиляции и критические синтаксические ошибки.

Предупреждение (Warning): указывает на то, что, возможно, возникли ошибочные условия, но сценарий после возникновения ошибки будет продолжать работу.

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

Если в файле php.ini включено отображение ошибок (display_errors = on), то сообщения об ошибках будут выводиться на экран, часто это самый быстрый способ по+ иска и отладки ошибок при создании приложения. Для реальных приложений следует отключать вывод ошибок на экран и вместо этого протоколировать их в журнале.

Синтаксические ошибки

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

Простые опечатки: очень легко напечатать вместо двоеточия или квадратной скобки точку с запятой или фигурную скобку. Приучите себя проверять синтак+ сис по мере ввода кода.

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

Надежный и понятный код 225

for ($myloop01 = 0; $myloop01<10; $myloop01++)

{

for ($myloop02 = 2; $myloop02<20; $myloop02++)

{

for ($myloop03 = 3; $myloop03<30; $myloop03++)

{

for ($myloop04 = 4; $myloop04<40; $myloop04++)

{

... Здесь еще какой-либо код...

}

}

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

for ($myloop01 = 0; $myloop01<10; $myloop01++)

{

for ($myloop02 = 2; $myloop02<20;$myloop02++)

{

for ($myloop03 = 3; $myloop03<30; $myloop03++)

{

for ($myloop04 = 4; $myloop04<40; $myloop04++)

{

... Здесь еще какой-либо код...

}

}

}

по отступам легко заметить недостающую скобку.

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

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

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

echo "Это начало строки с " . $number . " кавычками, как с одинарными, например, \', так и с двойными, например, \", а также кавычек в HTML,

например, <img src="image.gif">;

Две первые кавычки (одинарная и двойная) экранированы правильно, а две по+ следние в примере HTML+кода ++++++ неправильно. В дополнение к этому пропу+ щена завершающая двойная кавычка. При обработке данного оператора PHP сгенерирует синтаксическую ошибку.

Как уже отмечалось, синтаксические ошибки часто появляются при первом тести+ ровании кода. Хотя PHP предоставляет весьма выразительные сообщения об ошибках,

226 Глава 5

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

<?php

//генерирование синтаксической ошибки $line_of_code = "ошибка: нет точки с запятой"

?>

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

Parse error: parse error in /home/servata/www/error_test_file.php on line 3 (Синтаксическая ошибка: синтаксическая ошибка в файле

/home/servata/www/error_test_file.php в строке 3)

Это сообщение содержит описание ошибки и номер строки с ошибкой. Однако иногда номер может неверно указывать ошибочную строку, например, когда пропу+ щена фигурная скобка, как показано в следующем примере:

<?php

//генерирование синтаксической ошибки if ($my_test == 0) {

//какие-либо операторы

} else { ?> <html> <head>

<title></title>

</head>

<body>

какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br> какой-либо HTML-код<br>

</body>

</html>

При разборе данного кода PHP+интерпретатор генерирует следующее сообщение:

Parse error: parse error in /home/servata/www/error_test_file02.php on line 31 (Синтаксическая ошибка: синтаксическая ошибка в файле

/home/servata/www/error_test_file02.php в строке 31)

Каким бы информативным ни было сообщение, в данном конкретном случае но+ мер строки указан неверно, потому что код состоит только из 29 строк. Даже если по+ смотреть в конец файла, то можно не заметить, что проблема заключается в пропу+ щенной фигурной скобке, так как PHP+блок правильно закрыт до начала HTML+кода.

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

Надежный и понятный код 227

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

Логические ошибки

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

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

Логические ошибки возникают нерегулярно. Например, программа запускается

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

Следует представлять себе различия между типами логических ошибок. Некото+ рые логические ошибки проявляются во время выполнения программы и только при определенных условиях. Например, PHP+код выглядит хорошо и даже принимается

ивыполняется PHP+процессором, но при выполнении программы возникают ошиб+ ки, в результате которых программа преждевременно завершается. Такие ошибки называются ошибками времени выполнения. Ошибки времени выполнения, преждевре+ менно останавливающие программу, называются критическими (fatal). Все без исклю+ чения синтаксические ошибки являются критическими, но ошибки времени выпол+ нения, останавливающие сценарий только при определенных обстоятельствах, не всегда можно назвать критическими.

Логические ошибки второго типа фактически не останавливают программу, и она выполняется до завершения, но в конце возвращает некорректную информацию или вообще не возвращает никаких данных. Такие ошибки кратко можно охарактеризо+ вать как неожиданные ошибки вывода. Рассмотрим ошибки времени выполнения бо+ лее подробно.

Ошибки времени выполнения

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

228 Глава 5

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

Деление на нуль

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

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

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

Ниже приведен код очень простой формы, который показывает, что происходит, когда в сценарии выполняется деление на нуль. Запустите HTML+редактор, введите следующий код и сохраните созданный файл как divide_by_zero.php.

<html>

<head><title></title></head>

<body>

<b>Деление любого числа (кроме нуля)</b> <br>

<br>

<?php

if (isset($_POST['posted'])) {

$first_number = $_POST['first_number']; $second_number = $_POST['second_number'];

$answer = $first_number / $second_number; echo "Ответ: " . $answer . "<br>";

}

?>

<form method="POST" action="divide_by_zero.php">

<input type="hidden" name="posted" value="true">

Пожалуйста, введите первое число: <br>

<br>

<input name="first_number" type="text" value="0"><br>

Пожалуйста, введите второе число: <br>

<br>

<input name="second_number" type="text" value="0"><br>

Нажмите кнопку "Разделить" <br>

<br>

<input type="submit" value="Разделить"> </form>

</body>

</html>

Надежный и понятный код 229

При выполнении данного кода в браузере отображается страница, показанная на рис. 5.1.

Рис. 5.1.

Протестируйте форму как с числами, так и без. На рис. 5.2 показан результат по+ пытки деления на нуль.

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

Если пользователь вводит в данной форме (или оставляет) 0 в качестве первого значения, то никакой ошибки не возникает (ответ равен нулю). Однако даже если второе число вообще не введено, PHP все равно интерпретирует пустую строку как 0 и генерирует сообщение об ошибке. Одна из возможностей уменьшить вероятность возникновения ошибки заключается в том, чтобы установить в HTML+коде значения по умолчанию для полей первого и второго чисел равным 1, а не 0. Кроме того, мож+ но проверять входящие значения, чтобы убедиться, что они не равны нулю. (Проверка данных формы рассматривается в этой главе далее.)

Итак, в приложениях необходимо учитывать возможность деления на нуль, а так+ же другие математические функции, которые могут создавать проблемы, например, вычисление квадратного корня отрицательного числа.

230 Глава 5

Рис. 5.2.

Бесконечные циклы

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

При использовании циклических структур, таких как while и do while, в PHP возникает проблема: если заданное условие никогда не выполняется, то PHP обраба+ тывает цикл потенциально бесконечное число раз в пределах, заданных параметром max_execution_time (в файле php.ini). Если время выполнения сценария превыша+ ет значение max_execution_time, то PHP генерирует предупреждение и прекращает обработку. Как и любое сообщение об ошибке, это предупреждение может быть ото+ бражено и ясно сообщать о случившемся, однако восстановить работу программы при таких обстоятельствах не удастся. Рассмотрим следующий код, не запуская его:

$cntr=1; $test = True; while ($test)

{

$cntr++;

}

Надежный и понятный код 231

Пока переменная+счетчик ($cntr) увеличивается в каждой итерации цикла, пере+ менная $test не может получить значение False, поэтому данный цикл никогда не за+ кончится. Запуск такого цикла на Windows+сервере может легко привести к зависанию системы (Linux+машины с Web+сервером Apache справляются с такой ситуацией гораздо лучше, и все же когда время выполнения превысит значение max_execution_time, отображается предупреждение).

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

Логические ошибки вывода

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

Очень хорошим примером таких ошибок является использование десятичных дробей. Например, предположим, что пользователь должен ввести значение 0,0775 (налог на продажу в Калифорнии), но вместо этого вводит число 7,75. Можно пред+ ставить, как это повлияет на общую сумму налогов. Вместе с тем, ничто в данном сце+ нарии не вызывает автоматический вывод предупреждения или сообщения об ошиб+ ке; PHP просто выполнит вычисления и выдаст ответ. Предвидеть такие ситуации и предотвратить возникновение подобных ошибок должен программист, и только тщательное многократное тестирование поможет создать качественное приложение.

Функции, не возвращающие значений

При создании собственных функций (эта тема раскрывается в главе 6) можно включать оператор return, который инструктирует функцию о том, какое значение необходимо возвратить при вызове данной функции. Не все функции требуют нали+ чия данного оператора, поэтому о нем довольно легко забыть. А если оператор return не используется там, где он требуется, то функция вообще не будет возвращать ника+ кого значения.

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

Неправильный порядок аргументов функций

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

232 Глава 5

Присвоение значений вместо сравнения значений

Одной из широко распространенных ошибок в PHP является использование знака равенства для сравнения значений, когда фактически вместо этого происходит при+ сваивание значений. PHP в таких случаях не выводит никаких предупреждений, а про+ сто присваивает переменной значение и продолжает работу сценария с новым значени+ ем. Эта ошибка очень распространена в структурах if... then... else, например:

If ($my_value = $your_value) { //выполнить этот блок

} else {

//выполнить этот блок

}

К сожалению, ошибочность подобного кода не всегда очевидна, и поскольку код кажется верным (в конце концов, можно просто не заметить, что используется =, а не ==), особенно если программист знает другие языки, которые допускают использование знака = для сравнения значений, то избежать возникновения такой ошибки бывает нелегко. Не существует волшебного средства для разрешения данной проблемы; не+ обходимо просто быть внимательным: использовать знак = для присвоения значений, а == для сравнения.

Отладка и обработка ошибок в PHP5

В PHP5 появились новые функции try/catch, которые предоставляют новые ценные способы обработки ошибок в PHP (эти функции подробнее рассматриваются в конце данной главы), кроме того, PHP также предлагает более традиционные спо+ собы отладки и поиска ошибок, а также возможности их изящной обработки во время выполнения приложения. В данном разделе рассматриваются традиционные средства.

Предотвращение отображения конфиденциальной информации

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

Кроме того, не следует забывать о том, что другие приложения, которые исполь+ зуются PHP, могут сообщать еще больше информации об ошибках; PostGreSQL и дру+ гие базы данных могут очень точно описывать SQL+выражения, содержащие ошибки.

Создание собственных инструментов для отладки

Для написания HTML+ и PHP+кода можно использовать самые простые текстовые редакторы, но в этом случае разработчику будут недоступны развитые средства для предварительной компиляции кода, обнаружения синтаксических ошибок до выпол+ нения программы или отслеживания значений переменных во время ее выполнения. Однако не все потеряно, потому что существует несколько простых и эффективных способов сделать все это самостоятельно.

Надежный и понятный код 233

Использование оператора echo()

С помощью оператора echo можно выводить на экран значение, присвоенное какой+ либо переменной. Это можно делать внутри функций, внутри циклов, во время обычной обработки ++++++ по сути, можно помещать оператор echo почти в любой участок кода. А если идентифицировать местоположения того или иного оператора echo (например, вставив в него текст вроде ‘‘внутри цикла for’’ или ‘‘внутри второго оператора if’’), то в коде можно использовать множество операторов echo и знать, что происходит в каж+ дый момент выполнения программы. Например, если есть сценарий, принимающий от пользователя имя и адрес электронной почты, а затем обрабатывающий эти данные, то все происходящее во время обработки можно выяснить с помощью подобного кода:

<?php

echo "Имя :" . $name . "<br>";

echo "Email:" . $email . "<br>"; // обработка

echo "Имя после обработки:" . $name . "<br>"; echo "Email после обработки:" . $email . "<br>"; // дополнительная обработка

echo "Имя после дополнительной обработки:" . $name . "<br>"; echo "Email после дополнительной обработки:" . $email . "<br>";

?>

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

Ошибки внутри HTML-кода

Если PHP генерирует ошибку и отправляет предупреждение или сообщение о кри+ тической ошибке с каким+либо HTML+кодом, обработка которого была завершена до возникновения ошибки, то сообщение не всегда отображается на экране. Если ошиб+ ка возникает внутри HTML+тега или внутри генерируемого элемента управления формы, браузеры могут быть настолько снисходительными к HTML+ошибкам, что страница может отображаться даже несмотря на то, что на ней отсутствуют ожидае+ мые данные. Очень важно всякий раз при неверной работе сценария проверять HTML+код, получаемый браузером на предмет скрытых PHP+ошибок, а в ходе такой проверки стоит потратить время и убедиться, что ожидаемые значения (которые мо+ гут быть скрыты внутри исходного HTML+кода) также присутствуют.

Предположим, например, что используется PHP+код для подключения к базе дан+ ных, получения некоторых записей и последующего использования этих записей в цик+ ле for для создания HTML+элемента <select>. Известно, что элемент <select> необхо+ димо завершать закрывающим тегом </select> и что между этими тегами присутствуют элементы <option>. Если один из элементов <option> записан неверно (например, в нем присутствует PHP+сообщение об ошибке), то браузер просто проигнорирует данный эле+ мент. На экране пользователь увидит выпадающий список и все ‘‘хорошие’’ элементы <option>, но в HTML+коде можно будет заметить что+нибудь подобное:

<select name="select_customer_id">

<option value="1">Джон Доу</option> PHP-сообщение об ошибке

<option value="3">Джейн Доу</option> </select>

В данном случае полностью теряется клиент номер 2, но на экране сообщение об ошибке не отображается, хотя оно и отчетливо видно в исходном HTML+коде.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]