Why is this code causing a syntax error? Why can’t I catch the exception?
protected function RunQuery($sql) {
$pdo = $this->conn;
$stmt = $pdo->prepare($sql);
if($stmt) {
$stmt->execute($sql);
} else {
print_r("Unable to prepare the query");
}
catch(PDOException $e) {
print_r($e);
exit(0);
}
}
Don’t Panic
40.8k10 gold badges61 silver badges78 bronze badges
asked Feb 14, 2017 at 15:51
2
You need to have a try block before you can add a catch block. You will need to change your code to something like this:
protected function RunQuery ($sql) {
$pdo = $this->conn;
try
{
$stmt = $pdo->prepare($sql);
if ($stmt) {
$stmt->execute($sql);
} else {
print_r("Unable to prepare the query");
}
}
catch (PDOException $e) {
print_r($e);
exit(0);
}
}
More information about try & catch and how to work with exceptions can be found in the php documentation.
answered Feb 14, 2017 at 15:54
JerodevJerodev
31.5k11 gold badges87 silver badges106 bronze badges
Seems like you are missing an ‘}’ on the line above catch.
answered Feb 14, 2017 at 15:53
maesbnmaesbn
2073 silver badges6 bronze badges
2
I’ve searched for the answer to this, and from what I understand, I am missing a { or } somewhere. I keep reviewing my code, however, and I don’t see that I have a curly bracket issue. What’s going on? What I am trying to do is to get two different types of users accounts (admin, not admin).
<?php
include "header.html";
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
include('include/db-connect.php');
$email = $_POST['email'];
$pass = $_POST['pass'];
try {
if (empty($email) ||
empty($pass))
throw new Exception('Enter all
fields.');
// we're good to go
// SELECT from db
$query = "SELECT * FROM users
WHERE email_address = '$email'";
$result = $con->query($query);
if (!$result)
throw new Exception("Login failed. Please try again.");
$row = $result->fetch_assoc();
$user_id = $row['user_id'];
$hash = $row['user_password'];
$email = $row['email_address'];
$first_name = $row['first_name'];
$user_is_admin = $row['user_is_admin'];
// check password
if (password_verify($pass, $hash)) {
session_start();
$_SESSION['email'] = $email;
$_SESSION['user_id'] = $user_id;
$_SESSION['first_name'] = $first_name;
$_SESSION['user_is_admin'] = $user_is_admin;
if($user_is_admin == TRUE){
echo "yes";
//header("location: admin-user-test.php"); // if user auth is 1, send to admin
}
else if($user_is_admin == FALSE){
echo "no";
//header("location: user-homepage-test.php"); // if user auth is 0, send to admin
}
else {
throw new Exception("Login failed here also. Please try again.");
}
}
catch (Exception $ex) {
echo '<div class="error">' . $ex->getMessage() . '</div>';
}
}
?>
Антон Шевчук // Web-разработчик
Не совершает ошибок только тот, кто ничего не делает, и мы тому пример – трудимся не покладая рук над созданием рабочих мест для тестировщиков
О да, в этой статье я поведу свой рассказа об ошибках в PHP, и том как их обуздать.
Ошибки
Разновидности в семействе ошибок
Перед тем как приручать ошибки, я бы рекомендовал изучить каждый вид и отдельно обратить внимание на самых ярких представителей.
Чтобы ни одна ошибка не ушла незамеченной потребуется включить отслеживание всех ошибок с помощью функции error_reporting(), а с помощью директивы display_errors включить их отображение:
<?php error_reporting(E_ALL); ini_set('display_errors', 1);
Фатальные ошибки
Самый грозный вид ошибок – фатальные, они могут возникнуть как при компиляции, так и при работе парсера или PHP-скрипта, выполнение скрипта при этом прерывается.
E_PARSE
Это ошибка появляется, когда вы допускаете грубую ошибку синтаксиса и интерпретатор PHP не понимает, что вы от него хотите, например если не закрыли фигурную или круглую скобочку:
<?php /** Parse error: syntax error, unexpected end of file */ {
Или написали на непонятном языке:
<?php /** Parse error: syntax error, unexpected '...' (T_STRING) */ Тут будет ошибка парсера
Лишние скобочки тоже встречаются, и не важно круглые либо фигурные:
<?php /** Parse error: syntax error, unexpected '}' */ }
Отмечу один важный момент – код файла, в котором вы допустили parse error не будет выполнен, следовательно, если вы попытаетесь включить отображение ошибок в том же файле, где возникла ошибка парсера то это не сработает:
<?php // этот код не сработает error_reporting(E_ALL); ini_set('display_errors', 1); // т.к. вот тут ошибка парсера
E_ERROR
Это ошибка появляется, когда PHP понял что вы хотите, но сделать сие не получилось ввиду ряда причин, так же прерывает выполнение скрипта, при этом код до появления ошибки сработает:
Не был найден подключаемый файл:
/** Fatal error: require_once(): Failed opening required 'not-exists.php' (include_path='.:/usr/share/php:/usr/share/pear') */ require_once 'not-exists.php';
Было брошено исключение (что это за зверь, расскажу немного погодя), но не было обработано:
/** Fatal error: Uncaught exception 'Exception' */ throw new Exception();
При попытке вызвать несуществующий метод класса:
/** Fatal error: Call to undefined method stdClass::notExists() */ $stdClass = new stdClass(); $stdClass->notExists();
Отсутствия свободной памяти (больше, чем прописано в директиве memory_limit) или ещё чего-нить подобного:
/** Fatal Error: Allowed Memory Size */ $arr = array(); while (true) { $arr[] = str_pad(' ', 1024); }
Очень часто происходит при чтении либо загрузки больших файлов, так что будьте внимательны с вопросом потребляемой памяти
Рекурсивный вызов функции. В данном примере он закончился на 256-ой итерации, ибо так прописано в настройках xdebug:
/** Fatal error: Maximum function nesting level of '256' reached, aborting! */ function deep() { deep(); } deep();
Не фатальные
Данный вид не прерывает выполнение скрипта, но именно их обычно находит тестировщик, и именно они доставляют больше всего хлопот у начинающих разработчиков.
E_WARNING
Частенько встречается, когда подключаешь файл с использованием include
, а его не оказывается на сервере или ошиблись указывая путь к файлу:
/** Warning: include_once(): Failed opening 'not-exists.php' for inclusion */ include_once 'not-exists.php';
Бывает, если используешь неправильный тип аргументов при вызове функций:
/** Warning: join(): Invalid arguments passed */ join('string', 'string');
Их очень много, и перечислять все не имеет смысла…
E_NOTICE
Это самые распространенные ошибки, мало того, есть любители отключать вывод ошибок и клепают их целыми днями. Возникают при целом ряде тривиальных ошибок.
Когда обращаются к неопределенной переменной:
/** Notice: Undefined variable: a */ echo $a;
Когда обращаются к несуществующему элементу массива:
<?php /** Notice: Undefined index: a */ $b = array(); $b['a'];
Когда обращаются к несуществующей константе:
/** Notice: Use of undefined constant UNKNOWN_CONSTANT - assumed 'UNKNOWN_CONSTANT' */ echo UNKNOWN_CONSTANT;
Когда не конвертируют типы данных:
/** Notice: Array to string conversion */ echo array();
Для избежания подобных ошибок – будьте внимательней, и если вам IDE подсказывает о чём-то – не игнорируйте её:
E_STRICT
Это ошибки, которые научат вас писать код правильно, чтобы не было стыдно, тем более IDE вам эти ошибки сразу показывают. Вот например, если вызвали не статический метод как статику, то код будет работать, но это как-то неправильно, и возможно появление серьёзных ошибок, если в дальнейшем метод класса будет изменён, и появится обращение к $this
:
/** Strict standards: Non-static method Strict::test() should not be called statically */ class Strict { public function test() { echo 'Test'; } } Strict::test();
E_DEPRECATED
Так PHP будет ругаться, если вы используете устаревшие функции (т.е. те, что помечены как deprecated, и в следующем мажорном релизе их не будет):
/** Deprecated: Function split() is deprecated */ // популярная функция, всё никак не удалят из PHP // deprecated since 5.3 split(',', 'a,b');
В моём редакторе подобные функции будут зачёркнуты:
Обрабатываемые
Этот вид, которые разводит сам разработчик кода, я их уже давно не встречал, не рекомендую их вам заводить:
E_USER_ERROR
– критическая ошибкаE_USER_WARNING
– не критическая ошибкаE_USER_NOTICE
– сообщения которые не являются ошибками
Отдельно стоит отметить E_USER_DEPRECATED
– этот вид всё ещё используется очень часто для того, чтобы напомнить программисту, что метод или функция устарели и пора переписать код без использования оной. Для создания этой и подобных ошибок используется функция trigger_error():
/** * @deprecated Deprecated since version 1.2, to be removed in 2.0 */ function generateToken() { trigger_error('Function `generateToken` is deprecated, use class `Token` instead', E_USER_DEPRECATED); // ... // code ... // ... }
Теперь, когда вы познакомились с большинством видов и типов ошибок, пора озвучить небольшое пояснение по работе директивы
display_errors
:
- если
display_errors = on
, то в случае ошибки браузер получит html c текстом ошибки и кодом 200- если же
display_errors = off
, то для фатальных ошибок код ответа будет 500 и результат не будет возвращён пользователю, для остальных ошибок – код будет работать неправильно, но никому об этом не расскажет
Приручение
Для работы с ошибками в PHP существует 3 функции:
- set_error_handler() — устанавливает обработчик для ошибок, которые не обрывают работу скрипта (т.е. для не фатальных ошибок)
- error_get_last() — получает информацию о последней ошибке
- register_shutdown_function() — регистрирует обработчик который будет запущен при завершении работы скрипта. Данная функция не относится непосредственно к обработчикам ошибок, но зачастую используется именно для этого
Теперь немного подробностей об обработке ошибок с использованием set_error_handler()
, в качестве аргументов данная функция принимает имя функции, на которую будет возложена миссия по обработке ошибок и типы ошибок которые будут отслеживаться. Обработчиком ошибок может так же быть методом класса, или анонимной функцией, главное, чтобы он принимал следующий список аргументов:
$errno
– первый аргумент содержит тип ошибки в виде целого числа$errstr
– второй аргумент содержит сообщение об ошибке$errfile
– необязательный третий аргумент содержит имя файла, в котором произошла ошибка$errline
– необязательный четвертый аргумент содержит номер строки, в которой произошла ошибка$errcontext
– необязательный пятый аргумент содержит массив всех переменных, существующих в области видимости, где произошла ошибка
В случае если обработчик вернул true
, то ошибка будет считаться обработанной и выполнение скрипта продолжится, иначе — будет вызван стандартный обработчик, который логирует ошибку и в зависимости от её типа продолжит выполнение скрипта или завершит его. Вот пример обработчика:
<?php // включаем отображение всех ошибок, кроме E_NOTICE error_reporting(E_ALL & ~E_NOTICE); ini_set('display_errors', 1); // наш обработчик ошибок function myHandler($level, $message, $file, $line, $context) { // в зависимости от типа ошибки формируем заголовок сообщения switch ($level) { case E_WARNING: $type = 'Warning'; break; case E_NOTICE: $type = 'Notice'; break; default; // это не E_WARNING и не E_NOTICE // значит мы прекращаем обработку ошибки // далее обработка ложится на сам PHP return false; } // выводим текст ошибки echo "<h2>$type: $message</h2>"; echo "<p><strong>File</strong>: $file:$line</p>"; echo "<p><strong>Context</strong>: $". join(', $', array_keys($context))."</p>"; // сообщаем, что мы обработали ошибку, и дальнейшая обработка не требуется return true; } // регистрируем наш обработчик, он будет срабатывать на для всех типов ошибок set_error_handler('myHandler', E_ALL);
У вас не получится назначить более одной функции для обработки ошибок, хотя очень бы хотелось регистрировать для каждого типа ошибок свой обработчик, но нет – пишите один обработчик, и всю логику отображения для каждого типа описывайте уже непосредственно в нём
С обработчиком, который написан выше есть одна существенная проблема – он не ловит фатальные ошибки, и вместо сайта пользователи увидят лишь пустую страницу, либо, что ещё хуже, сообщение об ошибке. Дабы не допустить подобного сценария следует воспользоваться функцией register_shutdown_function() и с её помощью зарегистрировать функцию, которая всегда будет выполняться по окончанию работы скрипта:
function shutdown() { echo 'Этот текст будет всегда отображаться'; } register_shutdown_function('shutdown');
Данная функция будет срабатывать всегда!
Но вернёмся к ошибкам, для отслеживания появления в коде ошибки воспользуемся функцией error_get_last(), с её помощью можно получить информацию о последней выявленной ошибке, а поскольку фатальные ошибки прерывают выполнение кода, то они всегда будут выполнять роль “последних”:
function shutdown() { $error = error_get_last(); if ( // если в коде была допущена ошибка is_array($error) && // и это одна из фатальных ошибок in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR]) ) { // очищаем буфер вывода (о нём мы ещё поговорим в последующих статьях) while (ob_get_level()) { ob_end_clean(); } // выводим описание проблемы echo 'Сервер находится на техническом обслуживании, зайдите позже'; } } register_shutdown_function('shutdown');
Задание
Дополнить обработчик фатальных ошибок выводом исходного кода файла где была допущена ошибка, а так же добавьте подсветку синтаксиса выводимого кода.
О прожорливости
Проведём простой тест, и выясним – сколько драгоценных ресурсов кушает самая тривиальная ошибка:
/** * Этот код не вызывает ошибок */ // сохраняем параметры памяти и времени выполнения скрипта $memory = memory_get_usage(); $time= microtime(true); $a = ''; $arr = []; for ($i = 0; $i < 10000; $i++) { $arr[$a] = $i; } printf('%f seconds <br/>', microtime(true) - $time); echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes<br/>';
В результате запуска данного скрипта у меня получился вот такой результат:
0.002867 seconds 984 bytes
Теперь добавим ошибку в цикле:
/** * Этот код содержит ошибку */ // сохраняем параметры памяти и времени выполнения скрипта $memory = memory_get_usage(); $time= microtime(true); $a = ''; $arr = []; for ($i = 0; $i < 10000; $i++) { $arr[$b] = $i; // тут ошиблись с именем переменной } printf('%f seconds <br/>', microtime(true) - $time); echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes<br/>';
Результат ожидаемо хуже, и на порядок (даже на два порядка!):
0.263645 seconds 992 bytes
Вывод однозначен – ошибки в коде приводят к лишней прожорливости скриптов – так что во время разработки и тестирования приложения включайте отображение всех ошибок!
Тестирование проводил на PHP версии 5.6, в седьмой версии результат лучше – 0.0004 секунды против 0.0050 – разница только на один порядок, но в любом случае результат стоит прикладываемых усилий по исправлению ошибок
Где собака зарыта
В PHP есть спец символ «@» – оператор подавления ошибок, его используют дабы не писать обработку ошибок, а положится на корректное поведение PHP в случае чего:
<?php echo @UNKNOWN_CONSTANT;
При этом обработчик ошибок указанный в set_error_handler()
всё равно будет вызван, а факт того, что к ошибке было применено подавление можно отследить вызвав функцию error_reporting()
внутри обработчика, в этом случае она вернёт 0
.
Если вы в такой способ подавляете ошибки, то это уменьшает нагрузку на процессор в сравнении с тем, если вы их просто скрываете (см. сравнительный тест выше), но в любом случае, подавление ошибок это зло
Исключения
В эру PHP4 не было исключений (exceptions), всё было намного сложнее, и разработчики боролись с ошибками как могли, это было сражение не на жизнь, а на смерть… Окунуться в эту увлекательную историю противостояния можете в статье Исключительный код. Часть 1. Стоит ли её читать сейчас? Думаю да, ведь это поможет вам понять эволюцию языка, и раскроет всю прелесть исключений
Исключения — исключительные событие в PHP, в отличии от ошибок не просто констатируют наличие проблемы, а требуют от программиста дополнительных действий по обработке каждого конкретного случая.
К примеру, скрипт должен сохранить какие-то данные в кеш файл, если что-то пошло не так (нет доступа на запись, нет места на диске), генерируется исключение соответствующего типа, а в обработчике исключений принимается решение – сохранить в другое место или сообщить пользователю о проблеме.
Исключение – это объект который наследуется от класса Exception
, содержит текст ошибки, статус, а также может содержать ссылку на другое исключение которое стало первопричиной данного. Модель исключений в PHP схожа с используемыми в других языках программирования. Исключение можно инициировать (как говорят, “бросить”) при помощи оператора throw
, и можно перехватить (“поймать”) оператором catch
. Код генерирующий исключение, должен быть окружен блоком try
, для того чтобы можно было перехватить исключение. Каждый блок try
должен иметь как минимум один соответствующий ему блок catch
или finally
:
try { // код который может выбросить исключение if (rand(0, 1)) { throw new Exception('One') } else { echo 'Zero'; } } catch (Exception $e) { // код который может обработать исключение echo $e->getMessage(); }
В каких случаях стоит применять исключения:
- если в рамках одного метода/функции происходит несколько операций которые могут завершиться неудачей
- если используемый вами фреймверк или библиотека декларируют их использование
Для иллюстрации первого сценария возьмём уже озвученный пример функции для записи данных в файл – помешать нам может очень много факторов, а для того, чтобы сообщить выше стоящему коду в чем именно была проблема необходимо создать и выбросить исключение:
$directory = __DIR__ . DIRECTORY_SEPARATOR . 'logs'; // директории может не быть if (!is_dir($directory)) { throw new Exception('Directory `logs` is not exists'); } // может не быть прав на запись в директорию if (!is_writable($directory)) { throw new Exception('Directory `logs` is not writable'); } // возможно кто-то уже создал файл, и закрыл к нему доступ if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) { throw new Exception('System can't create log file'); } fputs($file, date('[H:i:s]') . " donen"); fclose($file);
Соответственно ловить данные исключения будем примерно так:
try { // код который пишет в файл // ... } catch (Exception $e) { // выводим текст ошибки echo 'Не получилось: '. $e->getMessage(); }
В данном примере приведен очень простой сценарий обработки исключений, когда у нас любая исключительная ситуация обрабатывается на один манер. Но зачастую – различные исключения требуют различного подхода к обработке, и тогда следует использовать коды исключений и задать иерархию исключений в приложении:
// исключения файловой системы class FileSystemException extends Exception {} // исключения связанные с директориями class DirectoryException extends FileSystemException { // коды исключений const DIRECTORY_NOT_EXISTS = 1; const DIRECTORY_NOT_WRITABLE = 2; } // исключения связанные с файлами class FileException extends FileSystemException {}
Теперь, если использовать эти исключения то можно получить следующий код:
try { // код который пишет в файл if (!is_dir($directory)) { throw new DirectoryException('Directory `logs` is not exists', DirectoryException::DIRECTORY_NOT_EXISTS); } if (!is_writable($directory)) { throw new DirectoryException('Directory `logs` is not writable', DirectoryException::DIRECTORY_NOT_WRITABLE); } if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) { throw new FileException('System can't open log file'); } fputs($file, date('[H:i:s]'') . " donen"); fclose($file); } catch (DirectoryException $e) { echo 'С директорией возникла проблема: '. $e->getMessage(); } catch (FileException $e) { echo 'С файлом возникла проблема: '. $e->getMessage(); } catch (FileSystemException $e) { echo 'Ошибка файловой системы: '. $e->getMessage(); } catch (Exception $e) { echo 'Ошибка сервера: '. $e->getMessage(); }
Важно помнить, что Exception — это прежде всего исключительное событие, иными словами исключение из правил. Не нужно использовать их для обработки очевидных ошибок, к примеру, для валидации введённых пользователем данных (хотя тут не всё так однозначно). При этом обработчик исключений должен быть написан в том месте, где он будет способен его обработать. К примеру, обработчик для исключений вызванных недоступностью файла для записи должен быть в методе, который отвечает за выбор файла или методе его вызывающем, для того что бы он имел возможность выбрать другой файл или другую директорию.
Так, а что будет если не поймать исключение? Вы получите “Fatal Error: Uncaught exception …”. Неприятно.
Чтобы избежать подобной ситуации следует использовать функцию set_exception_handler() и установить обработчик для исключений, которые брошены вне блока try-catch и не были обработаны. После вызова такого обработчика выполнение скрипта будет остановлено:
// в качестве обработчика событий // будем использовать анонимную функцию set_exception_handler(function($exception) { /** @var Exception $exception */ echo $exception->getMessage(), "<br/>n"; echo $exception->getFile(), ':', $exception->getLine(), "<br/>n"; echo $exception->getTraceAsString(), "<br/>n"; });
Ещё расскажу про конструкцию с использованием блока finally
– этот блок будет выполнен вне зависимости от того, было выброшено исключение или нет:
try { // код который может выбросить исключение } catch (Exception $e) { // код который может обработать исключение // если конечно оно появится } finally { // код, который будет выполнен при любом раскладе }
Для понимания того, что это нам даёт приведу следующий пример использования блока finally
:
try { // где-то глубоко внутри кода // соединение с базой данных $handler = mysqli_connect('localhost', 'root', '', 'test'); try { // при работе с БД возникла исключительная ситуация // ... throw new Exception('DB error'); } catch (Exception $e) { // исключение поймали, обработали на своём уровне // и должны его пробросить вверх, для дальнейшей обработки throw new Exception('Catch exception', 0, $e); } finally { // но, соединение с БД необходимо закрыть // будем делать это в блоке finally mysqli_close($handler); } // этот код не будет выполнен, если произойдёт исключение в коде выше echo "Ok"; } catch (Exception $e) { // ловим исключение, и выводим текст echo $e->getMessage(); echo "<br/>"; // выводим информацию о первоначальном исключении echo $e->getPrevious()->getMessage(); }
Т.е. запомните – блок finally
будет выполнен даже в том случае, если вы в блоке catch
пробрасываете исключение выше (собственно именно так он и задумывался).
Для вводной статьи информации в самый раз, кто жаждет ещё подробностей, то вы их найдёте в статье Исключительный код
Задание
Написать свой обработчик исключений, с выводом текста файла где произошла ошибка, и всё это с подсветкой синтаксиса, так же не забудьте вывести trace в читаемом виде. Для ориентира – посмотрите как это круто выглядит у whoops.
PHP7 – всё не так, как было раньше
Так, вот вы сейчас всю информацию выше усвоили и теперь я буду грузить вас нововведениями в PHP7, т.е. я буду рассказывать о том, с чем вы столкнётесь через год работы PHP разработчиком. Ранее я вам рассказывал и показывал на примерах какой костыль нужно соорудить, чтобы отлавливать критические ошибки, так вот – в PHP7 это решили исправить, но как обычно завязались на обратную совместимость кода, и получили хоть и универсальное решение, но оно далеко от идеала. А теперь по пунктам об изменениях:
- при возникновении фатальных ошибок типа
E_ERROR
или фатальных ошибок с возможностью обработкиE_RECOVERABLE_ERROR
PHP выбрасывает исключение - эти исключения не наследуют класс Exception (помните я говорил об обратной совместимости, это всё ради неё)
- эти исключения наследуют класс Error
- оба класса Exception и Error реализуют интерфейс Throwable
- вы не можете реализовать интерфейс Throwable в своём коде
Интерфейс Throwable
практически полностью повторяет нам Exception
:
interface Throwable { public function getMessage(): string; public function getCode(): int; public function getFile(): string; public function getLine(): int; public function getTrace(): array; public function getTraceAsString(): string; public function getPrevious(): Throwable; public function __toString(): string; }
Сложно? Теперь на примерах, возьмём те, что были выше и слегка модернизируем:
try { // файл, который вызывает ошибку парсера include 'e_parse_include.php'; } catch (Error $e) { var_dump($e); }
В результате ошибку поймаем и выведем:
object(ParseError)#1 (7) { ["message":protected] => string(48) "syntax error, unexpected 'будет' (T_STRING)" ["string":"Error":private] => string(0) "" ["code":protected] => int(0) ["file":protected] => string(49) "/www/education/error/e_parse_include.php" ["line":protected] => int(4) ["trace":"Error":private] => array(0) { } ["previous":"Error":private] => NULL }
Как видите – поймали исключение ParseError, которое является наследником исключения Error
, который реализует интерфейс Throwable
, в доме который построил Джек. Ещё есть другие, но не буду мучать – для наглядности приведу иерархию исключений:
interface Throwable |- Exception implements Throwable | |- ErrorException extends Exception | |- ... extends Exception | `- ... extends Exception `- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- ArithmeticError extends Error | `- DivisionByZeroError extends ArithmeticError `- AssertionError extends Error
TypeError – для ошибок, когда тип аргументов функции не совпадает с передаваемым типом:
try { (function(int $one, int $two) { return; })('one', 'two'); } catch (TypeError $e) { echo $e->getMessage(); }
ArithmeticError – могут возникнуть при математических операциях, к примеру когда результат вычисления превышает лимит выделенный для целого числа:
try { 1 << -1; } catch (ArithmeticError $e) { echo $e->getMessage(); }
DivisionByZeroError – ошибка деления на ноль:
try { 1 / 0; } catch (ArithmeticError $e) { echo $e->getMessage(); }
AssertionError – редкий зверь, появляется когда условие заданное в assert() не выполняется:
ini_set('zend.assertions', 1); ini_set('assert.exception', 1); try { assert(1 === 0); } catch (AssertionError $e) { echo $e->getMessage(); }
При настройках production-серверов, директивы
zend.assertions
иassert.exception
отключают, и это правильно
Задание
Написать универсальный обработчик ошибок для PHP7, который будет отлавливать все возможные исключения.
При написании данного раздела были использованы материалы из статьи Throwable Exceptions and Errors in PHP 7
Отладка
Иногда для отладки кода нужно отследить что происходило с переменной или объектом на определённом этапе, для этих целей есть функция debug_backtrace() и debug_print_backtrace() которые вернут историю вызовов функций/методов в обратном порядке:
<?php function example() { echo '<pre>'; debug_print_backtrace(); echo '</pre>'; } class ExampleClass { public static function method () { example(); } } ExampleClass::method();
В результате выполнения функции debug_print_backtrace()
будет выведен список вызовов приведших нас к данной точке:
#0 example() called at [/www/education/error/backtrace.php:10] #1 ExampleClass::method() called at [/www/education/error/backtrace.php:14]
Проверить код на наличие синтаксических ошибок можно с помощью функции php_check_syntax() или же команды php -l [путь к файлу]
, но я не встречал использования оных.
Assert
Отдельно хочу рассказать о таком экзотическом звере как assert() в PHP, собственно это кусочек контрактной методологии программирования, и дальше я расскажу вам как я никогда его не использовал
Первый случай – это когда вам надо написать TODO прямо в коде, да так, чтобы точно не забыть реализовать заданный функционал:
// включаем вывод ошибок error_reporting(E_ALL); ini_set('display_errors', 1); // включаем asserts ini_set('zend.assertions', 1); ini_set('assert.active', 1); assert(false, "Remove it!");
В результате выполнения данного кода получим E_WARNING
:
Warning: assert(): Remove it! failed
PHP7 можно переключить в режим exception, и вместо ошибки будет всегда появляться исключение AssertionError
:
// включаем asserts ini_set('zend.assertions', 1); ini_set('assert.active', 1); // переключаем на исключения ini_set('assert.exception', 1); assert(false, "Remove it!");
В результате ожидаемо получаем не пойманный AssertionError
. При необходимости, можно выбрасывать произвольное исключение:
assert(false, new Exception("Remove it!"));
Но я бы рекомендовал использовать метки
@TODO
, современные IDE отлично с ними работают, и вам не нужно будет прикладывать дополнительные усилия и ресурсы для работы с ними
Второй вариант использования – это создание некоего подобия TDD, но помните – это лишь подобие. Хотя, если сильно постараться, то можно получить забавный результат, который поможет в тестировании вашего кода:
// callback-функция для вывода информации в браузер function backlog($script, $line, $code, $message) { echo "<h3>$message</h3>"; highlight_string ($code); } // устанавливаем callback-функцию assert_options(ASSERT_CALLBACK, 'backlog'); // отключаем вывод предупреждений assert_options(ASSERT_WARNING, false); // пишем проверку и её описание assert("sqr(4) == 16", "When I send integer, function should return square of it"); // функция, которую проверяем function sqr($a) { return; // она не работает }
Третий теоретический вариант – это непосредственно контрактное программирование – когда вы описали правила использования своей библиотеки, но хотите точно убедится, что вас поняли правильно, и в случае чего сразу указать разработчику на ошибку (я вот даже не уверен, что правильно его понимаю, но пример кода вполне рабочий):
/** * Настройки соединения должны передаваться в следующем виде * * [ * 'host' => 'localhost', * 'port' => 3306, * 'name' => 'dbname', * 'user' => 'root', * 'pass' => '' * ] * * @param $settings */ function setupDb ($settings) { // проверяем настройки assert(isset($settings['host']), 'Db `host` is required'); assert(isset($settings['port']) && is_int($settings['port']), 'Db `port` is required, should be integer'); assert(isset($settings['name']), 'Db `name` is required, should be integer'); // соединяем с БД // ... } setupDb(['host' => 'localhost']);
Никогда не используйте
assert()
для проверки входных параметров, ведь фактическиassert()
интерпретирует строковую переменную (ведёт себя какeval()
), а это чревато PHP-инъекцией. И да, это правильное поведение, т.к. просто отключив assert’ы всё что передаётся внутрь будет проигнорировано, а если делать как в примере выше, то код будет выполняться, а внутрь отключенного assert’a будет передан булевый результат выполнения
Если у вас есть живой опыт использования assert()
– поделитесь со мной, буду благодарен. И да, вот вам ещё занимательно чтива по этой теме – PHP Assertions, с таким же вопросом в конце
В заключение
Я за вас напишу выводы из данной статьи:
- Ошибкам бой – их не должно быть в вашем коде
- Используйте исключения – работу с ними нужно правильно организовать и будет счастье
- Assert – узнали о них, и хорошо
P.S. Спасибо Максиму Слесаренко за помощь в написании статьи
Содержание
- PHP для начинающих. Обработка ошибок // PHP
- Ошибки
- Разновидности в семействе ошибок
- Фатальные ошибки
- Не фатальные
- Обрабатываемые
- Приручение
- О прожорливости
- Где собака зарыта
- Исключения
- PHP7 – всё не так, как было раньше
- Отладка
- Assert
- В заключение
PHP для начинающих. Обработка ошибок // PHP
Не совершает ошибок только тот, кто ничего не делает, и мы тому пример – трудимся не покладая рук над созданием рабочих мест для тестировщиков 🙂
О да, в этой статье я поведу свой рассказа об ошибках в PHP, и том как их обуздать.
Ошибки
Разновидности в семействе ошибок
Перед тем как приручать ошибки, я бы рекомендовал изучить каждый вид и отдельно обратить внимание на самых ярких представителей.
Чтобы ни одна ошибка не ушла незамеченной потребуется включить отслеживание всех ошибок с помощью функции error_reporting(), а с помощью директивы display_errors включить их отображение:
Фатальные ошибки
Самый грозный вид ошибок – фатальные, они могут возникнуть как при компиляции, так и при работе парсера или PHP-скрипта, выполнение скрипта при этом прерывается.
E_PARSE
Это ошибка появляется, когда вы допускаете грубую ошибку синтаксиса и интерпретатор PHP не понимает, что вы от него хотите, например если не закрыли фигурную или круглую скобочку:
Или написали на непонятном языке:
Лишние скобочки тоже встречаются, и не важно круглые либо фигурные:
Отмечу один важный момент – код файла, в котором вы допустили parse error не будет выполнен, следовательно, если вы попытаетесь включить отображение ошибок в том же файле, где возникла ошибка парсера то это не сработает:
E_ERROR
Это ошибка появляется, когда PHP понял что вы хотите, но сделать сие не получилось ввиду ряда причин, так же прерывает выполнение скрипта, при этом код до появления ошибки сработает:
Не был найден подключаемый файл:
Было брошено исключение (что это за зверь, расскажу немного погодя), но не было обработано:
При попытке вызвать несуществующий метод класса:
Отсутствия свободной памяти (больше, чем прописано в директиве memory_limit) или ещё чего-нить подобного:
Очень часто происходит при чтении либо загрузки больших файлов, так что будьте внимательны с вопросом потребляемой памяти
Рекурсивный вызов функции. В данном примере он закончился на 256-ой итерации, ибо так прописано в настройках xdebug:
Не фатальные
Данный вид не прерывает выполнение скрипта, но именно их обычно находит тестировщик, и именно они доставляют больше всего хлопот у начинающих разработчиков.
E_WARNING
Частенько встречается, когда подключаешь файл с использованием include , а его не оказывается на сервере или ошиблись указывая путь к файлу:
Бывает, если используешь неправильный тип аргументов при вызове функций:
Их очень много, и перечислять все не имеет смысла…
E_NOTICE
Это самые распространенные ошибки, мало того, есть любители отключать вывод ошибок и клепают их целыми днями. Возникают при целом ряде тривиальных ошибок.
Когда обращаются к неопределенной переменной:
Когда обращаются к несуществующему элементу массива:
Когда обращаются к несуществующей константе:
Когда не конвертируют типы данных:
Для избежания подобных ошибок – будьте внимательней, и если вам IDE подсказывает о чём-то – не игнорируйте её:
E_STRICT
Это ошибки, которые научат вас писать код правильно, чтобы не было стыдно, тем более IDE вам эти ошибки сразу показывают. Вот например, если вызвали не статический метод как статику, то код будет работать, но это как-то неправильно, и возможно появление серьёзных ошибок, если в дальнейшем метод класса будет изменён, и появится обращение к $this :
E_DEPRECATED
Так PHP будет ругаться, если вы используете устаревшие функции (т.е. те, что помечены как deprecated, и в следующем мажорном релизе их не будет):
В моём редакторе подобные функции будут зачёркнуты:
Обрабатываемые
Этот вид, которые разводит сам разработчик кода, я их уже давно не встречал, не рекомендую их вам заводить:
- E_USER_ERROR – критическая ошибка
- E_USER_WARNING – не критическая ошибка
- E_USER_NOTICE – сообщения которые не являются ошибками
Отдельно стоит отметить E_USER_DEPRECATED – этот вид всё ещё используется очень часто для того, чтобы напомнить программисту, что метод или функция устарели и пора переписать код без использования оной. Для создания этой и подобных ошибок используется функция trigger_error():
Теперь, когда вы познакомились с большинством видов и типов ошибок, пора озвучить небольшое пояснение по работе директивы display_errors :
- если display_errors = on , то в случае ошибки браузер получит html c текстом ошибки и кодом 200
- если же display_errors = off , то для фатальных ошибок код ответа будет 500 и результат не будет возвращён пользователю, для остальных ошибок – код будет работать неправильно, но никому об этом не расскажет
Приручение
Для работы с ошибками в PHP существует 3 функции:
- set_error_handler() — устанавливает обработчик для ошибок, которые не обрывают работу скрипта (т.е. для не фатальных ошибок)
- error_get_last() — получает информацию о последней ошибке
- register_shutdown_function() — регистрирует обработчик который будет запущен при завершении работы скрипта. Данная функция не относится непосредственно к обработчикам ошибок, но зачастую используется именно для этого
Теперь немного подробностей об обработке ошибок с использованием set_error_handler() , в качестве аргументов данная функция принимает имя функции, на которую будет возложена миссия по обработке ошибок и типы ошибок которые будут отслеживаться. Обработчиком ошибок может так же быть методом класса, или анонимной функцией, главное, чтобы он принимал следующий список аргументов:
- $errno – первый аргумент содержит тип ошибки в виде целого числа
- $errstr – второй аргумент содержит сообщение об ошибке
- $errfile – необязательный третий аргумент содержит имя файла, в котором произошла ошибка
- $errline – необязательный четвертый аргумент содержит номер строки, в которой произошла ошибка
- $errcontext – необязательный пятый аргумент содержит массив всех переменных, существующих в области видимости, где произошла ошибка
В случае если обработчик вернул true , то ошибка будет считаться обработанной и выполнение скрипта продолжится, иначе — будет вызван стандартный обработчик, который логирует ошибку и в зависимости от её типа продолжит выполнение скрипта или завершит его. Вот пример обработчика:
У вас не получится назначить более одной функции для обработки ошибок, хотя очень бы хотелось регистрировать для каждого типа ошибок свой обработчик, но нет – пишите один обработчик, и всю логику отображения для каждого типа описывайте уже непосредственно в нём
С обработчиком, который написан выше есть одна существенная проблема – он не ловит фатальные ошибки, и вместо сайта пользователи увидят лишь пустую страницу, либо, что ещё хуже, сообщение об ошибке. Дабы не допустить подобного сценария следует воспользоваться функцией register_shutdown_function() и с её помощью зарегистрировать функцию, которая всегда будет выполняться по окончанию работы скрипта:
Данная функция будет срабатывать всегда!
Но вернёмся к ошибкам, для отслеживания появления в коде ошибки воспользуемся функцией error_get_last(), с её помощью можно получить информацию о последней выявленной ошибке, а поскольку фатальные ошибки прерывают выполнение кода, то они всегда будут выполнять роль “последних”:
Задание
Дополнить обработчик фатальных ошибок выводом исходного кода файла где была допущена ошибка, а так же добавьте подсветку синтаксиса выводимого кода.
О прожорливости
Проведём простой тест, и выясним – сколько драгоценных ресурсов кушает самая тривиальная ошибка:
В результате запуска данного скрипта у меня получился вот такой результат:
Теперь добавим ошибку в цикле:
Результат ожидаемо хуже, и на порядок (даже на два порядка!):
Вывод однозначен – ошибки в коде приводят к лишней прожорливости скриптов – так что во время разработки и тестирования приложения включайте отображение всех ошибок!
Тестирование проводил на PHP версии 5.6, в седьмой версии результат лучше – 0.0004 секунды против 0.0050 – разница только на один порядок, но в любом случае результат стоит прикладываемых усилий по исправлению ошибок
Где собака зарыта
В PHP есть спец символ «@» – оператор подавления ошибок, его используют дабы не писать обработку ошибок, а положится на корректное поведение PHP в случае чего:
При этом обработчик ошибок указанный в set_error_handler() всё равно будет вызван, а факт того, что к ошибке было применено подавление можно отследить вызвав функцию error_reporting() внутри обработчика, в этом случае она вернёт 0 .
Если вы в такой способ подавляете ошибки, то это уменьшает нагрузку на процессор в сравнении с тем, если вы их просто скрываете (см. сравнительный тест выше), но в любом случае, подавление ошибок это зло
Исключения
В эру PHP4 не было исключений (exceptions), всё было намного сложнее, и разработчики боролись с ошибками как могли, это было сражение не на жизнь, а на смерть… Окунуться в эту увлекательную историю противостояния можете в статье Исключительный код. Часть 1. Стоит ли её читать сейчас? Думаю да, ведь это поможет вам понять эволюцию языка, и раскроет всю прелесть исключений
Исключения — исключительные событие в PHP, в отличии от ошибок не просто констатируют наличие проблемы, а требуют от программиста дополнительных действий по обработке каждого конкретного случая.
К примеру, скрипт должен сохранить какие-то данные в кеш файл, если что-то пошло не так (нет доступа на запись, нет места на диске), генерируется исключение соответствующего типа, а в обработчике исключений принимается решение – сохранить в другое место или сообщить пользователю о проблеме.
Исключение – это объект который наследуется от класса Exception , содержит текст ошибки, статус, а также может содержать ссылку на другое исключение которое стало первопричиной данного. Модель исключений в PHP схожа с используемыми в других языках программирования. Исключение можно инициировать (как говорят, “бросить”) при помощи оператора throw , и можно перехватить (“поймать”) оператором catch . Код генерирующий исключение, должен быть окружен блоком try , для того чтобы можно было перехватить исключение. Каждый блок try должен иметь как минимум один соответствующий ему блок catch или finally :
В каких случаях стоит применять исключения:
- если в рамках одного метода/функции происходит несколько операций которые могут завершиться неудачей
- если используемый вами фреймверк или библиотека декларируют их использование
Для иллюстрации первого сценария возьмём уже озвученный пример функции для записи данных в файл – помешать нам может очень много факторов, а для того, чтобы сообщить выше стоящему коду в чем именно была проблема необходимо создать и выбросить исключение:
Соответственно ловить данные исключения будем примерно так:
В данном примере приведен очень простой сценарий обработки исключений, когда у нас любая исключительная ситуация обрабатывается на один манер. Но зачастую – различные исключения требуют различного подхода к обработке, и тогда следует использовать коды исключений и задать иерархию исключений в приложении:
Теперь, если использовать эти исключения то можно получить следующий код:
Важно помнить, что Exception — это прежде всего исключительное событие, иными словами исключение из правил. Не нужно использовать их для обработки очевидных ошибок, к примеру, для валидации введённых пользователем данных (хотя тут не всё так однозначно). При этом обработчик исключений должен быть написан в том месте, где он будет способен его обработать. К примеру, обработчик для исключений вызванных недоступностью файла для записи должен быть в методе, который отвечает за выбор файла или методе его вызывающем, для того что бы он имел возможность выбрать другой файл или другую директорию.
Так, а что будет если не поймать исключение? Вы получите “Fatal Error: Uncaught exception …”. Неприятно.
Чтобы избежать подобной ситуации следует использовать функцию set_exception_handler() и установить обработчик для исключений, которые брошены вне блока try-catch и не были обработаны. После вызова такого обработчика выполнение скрипта будет остановлено:
Ещё расскажу про конструкцию с использованием блока finally – этот блок будет выполнен вне зависимости от того, было выброшено исключение или нет:
Для понимания того, что это нам даёт приведу следующий пример использования блока finally :
Т.е. запомните – блок finally будет выполнен даже в том случае, если вы в блоке catch пробрасываете исключение выше (собственно именно так он и задумывался).
Для вводной статьи информации в самый раз, кто жаждет ещё подробностей, то вы их найдёте в статье Исключительный код 😉
Задание
Написать свой обработчик исключений, с выводом текста файла где произошла ошибка, и всё это с подсветкой синтаксиса, так же не забудьте вывести trace в читаемом виде. Для ориентира – посмотрите как это круто выглядит у whoops.
PHP7 – всё не так, как было раньше
Так, вот вы сейчас всю информацию выше усвоили и теперь я буду грузить вас нововведениями в PHP7, т.е. я буду рассказывать о том, с чем вы столкнётесь через год работы PHP разработчиком. Ранее я вам рассказывал и показывал на примерах какой костыль нужно соорудить, чтобы отлавливать критические ошибки, так вот – в PHP7 это решили исправить, но как обычно завязались на обратную совместимость кода, и получили хоть и универсальное решение, но оно далеко от идеала. А теперь по пунктам об изменениях:
- при возникновении фатальных ошибок типа E_ERROR или фатальных ошибок с возможностью обработки E_RECOVERABLE_ERROR PHP выбрасывает исключение
- эти исключения не наследуют класс Exception (помните я говорил об обратной совместимости, это всё ради неё)
- эти исключения наследуют класс Error
- оба класса Exception и Error реализуют интерфейс Throwable
- вы не можете реализовать интерфейс Throwable в своём коде
Интерфейс Throwable практически полностью повторяет нам Exception :
Сложно? Теперь на примерах, возьмём те, что были выше и слегка модернизируем:
В результате ошибку поймаем и выведем:
Как видите – поймали исключение ParseError, которое является наследником исключения Error , который реализует интерфейс Throwable , в доме который построил Джек. Ещё есть другие, но не буду мучать – для наглядности приведу иерархию исключений:
TypeError – для ошибок, когда тип аргументов функции не совпадает с передаваемым типом:
ArithmeticError – могут возникнуть при математических операциях, к примеру когда результат вычисления превышает лимит выделенный для целого числа:
AssertionError – редкий зверь, появляется когда условие заданное в assert() не выполняется:
При настройках production-серверов, директивы zend.assertions и assert.exception отключают, и это правильно
Задание
Написать универсальный обработчик ошибок для PHP7, который будет отлавливать все возможные исключения.
При написании данного раздела были использованы материалы из статьи Throwable Exceptions and Errors in PHP 7
Отладка
Иногда для отладки кода нужно отследить что происходило с переменной или объектом на определённом этапе, для этих целей есть функция debug_backtrace() и debug_print_backtrace() которые вернут историю вызовов функций/методов в обратном порядке:
В результате выполнения функции debug_print_backtrace() будет выведен список вызовов приведших нас к данной точке:
Проверить код на наличие синтаксических ошибок можно с помощью функции php_check_syntax() или же команды php -l [путь к файлу] , но я не встречал использования оных.
Assert
Отдельно хочу рассказать о таком экзотическом звере как assert() в PHP, собственно это кусочек контрактной методологии программирования, и дальше я расскажу вам как я никогда его не использовал 🙂
Первый случай – это когда вам надо написать TODO прямо в коде, да так, чтобы точно не забыть реализовать заданный функционал:
В результате выполнения данного кода получим E_WARNING :
PHP7 можно переключить в режим exception, и вместо ошибки будет всегда появляться исключение AssertionError :
В результате ожидаемо получаем не пойманный AssertionError . При необходимости, можно выбрасывать произвольное исключение:
Но я бы рекомендовал использовать метки @TODO , современные IDE отлично с ними работают, и вам не нужно будет прикладывать дополнительные усилия и ресурсы для работы с ними
Второй вариант использования – это создание некоего подобия TDD, но помните – это лишь подобие. Хотя, если сильно постараться, то можно получить забавный результат, который поможет в тестировании вашего кода:
Третий теоретический вариант – это непосредственно контрактное программирование – когда вы описали правила использования своей библиотеки, но хотите точно убедится, что вас поняли правильно, и в случае чего сразу указать разработчику на ошибку (я вот даже не уверен, что правильно его понимаю, но пример кода вполне рабочий):
Никогда не используйте assert() для проверки входных параметров, ведь фактически assert() интерпретирует строковую переменную (ведёт себя как eval() ), а это чревато PHP-инъекцией. И да, это правильное поведение, т.к. просто отключив assert’ы всё что передаётся внутрь будет проигнорировано, а если делать как в примере выше, то код будет выполняться, а внутрь отключенного assert’a будет передан булевый результат выполнения
Если у вас есть живой опыт использования assert() – поделитесь со мной, буду благодарен. И да, вот вам ещё занимательно чтива по этой теме – PHP Assertions, с таким же вопросом в конце 🙂
В заключение
Я за вас напишу выводы из данной статьи:
- Ошибкам бой – их не должно быть в вашем коде
- Используйте исключения – работу с ними нужно правильно организовать и будет счастье
- Assert – узнали о них, и хорошо
Источник
PHP для начинающих. Обработка ошибок +32
PHP
Рекомендация: подборка платных и бесплатных курсов Java — https://katalog-kursov.ru/
Не совершает ошибок только тот, кто ничего не делает, и мы тому пример — сидим и трудимся не покладая рук, читаем Хабр
В этой статье я поведу свой рассказа об ошибках в PHP, и о том как их обуздать.
Ошибки
Разновидности в семействе ошибок
Перед тем как приручать ошибки, я бы рекомендовал изучить каждый вид и отдельно обратить внимание на самых ярких представителей.
Чтобы ни одна ошибка не ушла незамеченной потребуется включить отслеживание всех ошибок с помощью функции error_reporting(), а с помощью директивы display_errors включить их отображение:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
Фатальные ошибки
Самый грозный вид ошибок — фатальные, они могут возникнуть как при компиляции, так и при работе парсера или PHP-скрипта, выполнение скрипта при этом прерывается.
E_PARSE
Это ошибка появляется, когда вы допускаете грубую ошибку синтаксиса и интерпретатор PHP не понимает, что вы от него хотите, например если не закрыли фигурную или круглую скобочку:
<?php
/**
* Parse error: syntax error, unexpected end of file
*/
{
Или написали на непонятном языке:
<?php
/**
* Parse error: syntax error, unexpected '...' (T_STRING)
*/
Тут будет ошибка парсера
Лишние скобочки тоже встречаются, и не так важно круглые либо фигурные:
<?php
/**
* Parse error: syntax error, unexpected '}'
*/
}
Отмечу один важный момент — код файла, в котором вы допустили parse error не будет выполнен, следовательно, если вы попытаетесь включить отображение ошибок в том же файле, где возникла ошибка парсера то это не сработает:
<?php
// этот код не сработает
error_reporting(E_ALL);
ini_set('display_errors', 1);
// т.к. вот тут
ошибка парсера
E_ERROR
Это ошибка появляется, когда PHP понял что вы хотите, но сделать сие не получилось ввиду ряда причин. Эта ошибка так же прерывает выполнение скрипта, при этом код до появления ошибки сработает:
Не был найден подключаемый файл:
/**
* Fatal error: require_once(): Failed opening required 'not-exists.php'
* (include_path='.:/usr/share/php:/usr/share/pear')
*/
require_once 'not-exists.php';
Было брошено исключение (что это за зверь, расскажу немного погодя), но не было обработано:
/**
* Fatal error: Uncaught exception 'Exception'
*/
throw new Exception();
При попытке вызвать несуществующий метод класса:
/**
* Fatal error: Call to undefined method stdClass::notExists()
*/
$stdClass = new stdClass();
$stdClass->notExists();
Отсутствия свободной памяти (больше, чем прописано в директиве memory_limit) или ещё чего-нить подобного:
/**
* Fatal Error: Allowed Memory Size
*/
$arr = array();
while (true) {
$arr[] = str_pad(' ', 1024);
}
Очень часто встречается при чтении либо загрузки больших файлов, так что будьте внимательны с вопросом потребляемой памяти
Рекурсивный вызов функции. В данном примере он закончился на 256-ой итерации, ибо так прописано в настройках xdebug (да, данная ошибка может проявиться в таком виде только при включении xdebug расширения):
/**
* Fatal error: Maximum function nesting level of '256' reached, aborting!
*/
function deep() {
deep();
}
deep();
Не фатальные
Данный вид не прерывает выполнение скрипта, но именно их обычно находит тестировщик. Именно такие ошибки доставляют больше всего хлопот начинающим разработчикам.
E_WARNING
Частенько встречается, когда подключаешь файл с использованием include
, а его не оказывается на сервере или вы ошиблись указывая путь к файлу:
/**
* Warning: include_once(): Failed opening 'not-exists.php' for inclusion
*/
include_once 'not-exists.php';
Бывает, если используешь неправильный тип аргументов при вызове функций:
/**
* Warning: join(): Invalid arguments passed
*/
join('string', 'string');
Их очень много, и перечислять все не имеет смысла…
E_NOTICE
Это самые распространенные ошибки, мало того, есть любители отключать вывод ошибок и клепают их целыми днями. Возникают при целом ряде тривиальных ошибок.
Когда обращаются к неопределенной переменной:
/**
* Notice: Undefined variable: a
*/
echo $a;
Когда обращаются к несуществующему элементу массива:
/**
* Notice: Undefined index: a
*/
$b = [];
$b['a'];
Когда обращаются к несуществующей константе:
/**
* Notice: Use of undefined constant UNKNOWN_CONSTANT - assumed 'UNKNOWN_CONSTANT'
*/
echo UNKNOWN_CONSTANT;
Когда не конвертируют типы данных:
/**
* Notice: Array to string conversion
*/
echo array();
Для избежания подобных ошибок — будьте внимательней, и если вам IDE подсказывает о чём-то — не игнорируйте её:
E_STRICT
Это ошибки, которые научат вас писать код правильно, чтобы не было стыдно, тем более IDE вам эти ошибки сразу показывает. Вот например, если вызвали не статический метод как статику, то код будет работать, но это как-то неправильно, и возможно появление серьёзных ошибок, если в дальнейшем метод класса будет изменён, и появится обращение к $this
:
/**
* Strict standards: Non-static method Strict::test() should not be called statically
*/
class Strict {
public function test() {
echo "Test";
}
}
Strict::test();
Данный тип ошибок актуален для PHP версии 5.6, и практически все их выпилили из
7-ки. Почитать подробней можно в соответствующей RFC. Если кто знает где ещё остались данные ошибки, то напишите в комментариях
E_DEPRECATED
Так PHP будет ругаться, если вы используете устаревшие функции (т.е. те, что помечены как deprecated, и в следующем мажорном релизе их не будет):
/**
* Deprecated: Function split() is deprecated
*/
// данная функция, удалена из PHP 7.0
// считается устаревшей с PHP 5.3
split(',', 'a,b');
В моём редакторе подобные функции будут зачёркнуты:
Пользовательские
Этот вид, которые «разводит» сам разработчик кода, я уже давно их не встречал, и не рекомендую вам ими злоупотреблять:
E_USER_ERROR
— критическая ошибкаE_USER_WARNING
— не критическая ошибкаE_USER_NOTICE
— сообщения которые не являются ошибками
Отдельно стоит отметить E_USER_DEPRECATED
— этот вид всё ещё используется очень часто для того, чтобы напомнить программисту, что метод или функция устарели и пора переписать код без использования оной. Для создания этой и подобных ошибок используется функция trigger_error():
/**
* @deprecated Deprecated since version 1.2, to be removed in 2.0
*/
function generateToken() {
trigger_error('Function `generateToken` is deprecated, use class `Token` instead', E_USER_DEPRECATED);
// ...
// code ...
// ...
}
Теперь, когда вы познакомились с большинством видов и типов ошибок, пора озвучить небольшое пояснение по работе директивы
display_errors
:
- если
display_errors = on
, то в случае ошибки браузер получит html c текстом ошибки и кодом 200- если же
display_errors = off
, то для фатальных ошибок код ответа будет 500 и результат не будет возвращён пользователю, для остальных ошибок — код будет работать неправильно, но никому об этом не расскажет
Приручение
Для работы с ошибками в PHP существует 3 функции:
- set_error_handler() — устанавливает обработчик для ошибок, которые не обрывают работу скрипта (т.е. для не фатальных ошибок)
- error_get_last() — получает информацию о последней ошибке
- register_shutdown_function() — регистрирует обработчик который будет запущен при завершении работы скрипта. Данная функция не относится непосредственно к обработчикам ошибок, но зачастую используется именно для этого
Теперь немного подробностей об обработке ошибок с использованием set_error_handler()
, в качестве аргументов данная функция принимает имя функции, на которую будет возложена миссия по обработке ошибок и типы ошибок которые будут отслеживаться. Обработчиком ошибок может так же быть методом класса, или анонимной функцией, главное, чтобы он принимал следующий список аргументов:
$errno
— первый аргумент содержит тип ошибки в виде целого числа$errstr
— второй аргумент содержит сообщение об ошибке$errfile
— необязательный третий аргумент содержит имя файла, в котором произошла ошибка$errline
— необязательный четвертый аргумент содержит номер строки, в которой произошла ошибка$errcontext
— необязательный пятый аргумент содержит массив всех переменных, существующих в области видимости, где произошла ошибка
В случае если обработчик вернул true
, то ошибка будет считаться обработанной и выполнение скрипта продолжится, иначе — будет вызван стандартный обработчик, который логирует ошибку и в зависимости от её типа продолжит выполнение скрипта или завершит его. Вот пример обработчика:
<?php
// включаем отображение всех ошибок, кроме E_NOTICE
error_reporting(E_ALL & ~E_NOTICE);
ini_set('display_errors', 1);
// наш обработчик ошибок
function myHandler($level, $message, $file, $line, $context) {
// в зависимости от типа ошибки формируем заголовок сообщения
switch ($level) {
case E_WARNING:
$type = 'Warning';
break;
case E_NOTICE:
$type = 'Notice';
break;
default;
// это не E_WARNING и не E_NOTICE
// значит мы прекращаем обработку ошибки
// далее обработка ложится на сам PHP
return false;
}
// выводим текст ошибки
echo "<h2>$type: $message</h2>";
echo "<p><strong>File</strong>: $file:$line</p>";
echo "<p><strong>Context</strong>: $". join(', $',
array_keys($context))."</p>";
// сообщаем, что мы обработали ошибку, и дальнейшая обработка не требуется
return true;
}
// регистрируем наш обработчик, он будет срабатывать на для всех типов ошибок
set_error_handler('myHandler', E_ALL);
У вас не получится назначить более одной функции для обработки ошибок, хотя очень бы хотелось регистрировать для каждого типа ошибок свой обработчик, но нет — пишите один обработчик, и всю логику отображения для каждого типа описывайте уже непосредственно в нём
С обработчиком, который написан выше есть одна существенная проблема — он не ловит фатальные ошибки, и при таких ошибках вместо сайта пользователи увидят лишь пустую страницу, либо, что ещё хуже, сообщение об ошибке. Дабы не допустить подобного сценария следует воспользоваться функцией register_shutdown_function() и с её помощью зарегистрировать функцию, которая всегда будет выполняться по окончанию работы скрипта:
function shutdown() {
echo 'Этот текст будет всегда отображаться';
}
register_shutdown_function('shutdown');
Данная функция будет срабатывать всегда!
Но вернёмся к ошибкам, для отслеживания появления в коде ошибки воспользуемся функцией error_get_last(), с её помощью можно получить информацию о последней выявленной ошибке, а поскольку фатальные ошибки прерывают выполнение кода, то они всегда будут выполнять роль «последних»:
function shutdown() {
$error = error_get_last();
if (
// если в коде была допущена ошибка
is_array($error) &&
// и это одна из фатальных ошибок
in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])
) {
// очищаем буфер вывода (о нём мы ещё поговорим в последующих статьях)
while (ob_get_level()) {
ob_end_clean();
}
// выводим описание проблемы
echo "Сервер находится на техническом обслуживании, зайдите позже";
}
}
register_shutdown_function('shutdown');
Хотел обратить внимание, что данный код хоть ещё и встречается для обработки ошибок, и вы возможно вы даже с ним столкнётесь, но он потерял актуальность начиная с 7-ой версии PHP. Что пришло на замену я расскажу чуть погодя.
Задание
Дополнить обработчик фатальных ошибок выводом исходного кода файла где была допущена ошибка, а так же добавьте подсветку синтаксиса выводимого кода.
О прожорливости
Проведём простой тест, и выясним — сколько драгоценных ресурсов кушает самая тривиальная ошибка:
/**
* Этот код не вызывает ошибок
*/
// засекаем время выполнения скрипта
$time= microtime(true);
define('AAA', 'AAA');
$arr = [];
for ($i = 0; $i < 10000; $i++) {
$arr[AAA] = $i;
}
printf('%f seconds <br/>', microtime(true) - $time);
В результате запуска данного скрипта у меня получился вот такой результат:
0.002867 seconds
Теперь добавим ошибку в цикле:
/**
* Этот код содержит ошибку
*/
// засекаем время выполнения скрипта
$time= microtime(true);
$arr = [];
for ($i = 0; $i < 10000; $i++) {
$arr[BBB] = $i; // тут используем константанту, которая у нас не объявлена
}
printf('%f seconds <br/>', microtime(true) - $time);
Результат ожидаемо хуже, и на порядок (даже на два порядка!):
0.263645 seconds
Вывод однозначен — ошибки в коде приводят к лишней прожорливости скриптов — так что во время разработки и тестирования приложения включайте отображение всех ошибок!
Тестирование проводил на различных версиях PHP и везде разница в десятки раз, так что пусть это будет ещё одним поводом для исправления всех ошибок в коде
Где собака зарыта
В PHP есть спец символ «@» — оператор подавления ошибок, его используют дабы не писать обработку ошибок, а положится на корректное поведение PHP в случае чего:
<?php
echo @UNKNOWN_CONSTANT;
При этом обработчик ошибок указанный в set_error_handler()
всё равно будет вызван, а факт того, что к ошибке было применено подавление можно отследить вызвав функцию error_reporting()
внутри обработчика, в этом случае она вернёт 0
.
Если вы в такой способ подавляете ошибки, то это уменьшает нагрузку на процессор в сравнении с тем, если вы их просто скрываете (см. сравнительный тест выше), но в любом случае, подавление ошибок это зло
Задание
Проверьте, как влияет подавление ошибки с помощью @
на предыдущий пример с циклом.
Исключения
В эру PHP4 не было исключений (exceptions), всё было намного сложнее, и разработчики боролись с ошибками как могли, это было сражение не на жизнь, а на смерть… Окунуться в эту увлекательную историю противостояния можете в статье Исключительный код. Часть 1. Стоит ли её читать сейчас? Не могу дать однозначный ответ, лишь хочу заметить, что это поможет вам понять эволюцию языка, и раскроет всю прелесть исключений.
Исключения — исключительные событие в PHP, в отличии от ошибок не просто констатируют наличие проблемы, а требуют от программиста дополнительных действий по обработке каждого конкретного случая.
К примеру, скрипт должен сохранить какие-то данные в кеш файл, если что-то пошло не так (нет доступа на запись, нет места на диске), генерируется исключение соответствующего типа, а в обработчике исключений принимается решение — сохранить в другое место или сообщить пользователю о проблеме.
Исключение — это объект класса Exception
либо одного из многих его наследников, содержит текст ошибки, статус, а также может содержать ссылку на другое исключение которое стало первопричиной данного. Модель исключений в PHP схожа с используемыми в других языках программирования. Исключение можно инициировать (как говорят, «бросить») при помощи оператора throw
, и можно перехватить («поймать») оператором catch
. Код генерирующий исключение, должен быть окружен блоком try
, для того чтобы можно было перехватить исключение. Каждый блок try
должен иметь как минимум один соответствующий ему блок catch
или finally
:
try {
// код который может выбросить исключение
if (random_int(0, 1)) {
throw new Exception("One");
}
echo "Zero"
} catch (Exception $e) {
// код который может обработать исключение
echo $e->getMessage();
}
В каких случаях стоит применять исключения:
- если в рамках одного метода/функции происходит несколько операций которые могут завершиться неудачей
- если используемый вами фреймворк или библиотека декларируют их использование
Для иллюстрации первого сценария возьмём уже озвученный пример функции для записи данных в файл — помешать нам может очень много факторов, а для того, чтобы сообщить выше стоящему коду в чем именно была проблема необходимо создать и выбросить исключение:
$directory = __DIR__ . DIRECTORY_SEPARATOR . 'logs';
// директории может не быть
if (!is_dir($directory)) {
throw new Exception('Directory `logs` is not exists');
}
// может не быть прав на запись в директорию
if (!is_writable($directory)) {
throw new Exception('Directory `logs` is not writable');
}
// возможно кто-то уже создал файл, и закрыл к нему доступ
if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) {
throw new Exception('System can't create log file');
}
fputs($file, date("[H:i:s]") . " donen");
fclose($file);
Соответственно ловить данные исключения будем примерно так:
try {
// код который пишет в файл
// ...
} catch (Exception $e) {
// выводим текст ошибки
echo "Не получилось: ". $e->getMessage();
}
В данном примере приведен очень простой сценарий обработки исключений, когда у нас любая исключительная ситуация обрабатывается на один манер. Но зачастую, различные исключения требуют различного подхода к обработке, и тогда следует использовать коды исключений и задать иерархию исключений в приложении:
// исключения файловой системы
class FileSystemException extends Exception {}
// исключения связанные с директориями
class DirectoryException extends FileSystemException {
// коды исключений
const DIRECTORY_NOT_EXISTS = 1;
const DIRECTORY_NOT_WRITABLE = 2;
}
// исключения связанные с файлами
class FileException extends FileSystemException {}
Теперь, если использовать эти исключения то можно получить следующий код:
try {
// код который пишет в файл
if (!is_dir($directory)) {
throw new DirectoryException('Directory `logs` is not exists', DirectoryException::DIRECTORY_NOT_EXISTS);
}
if (!is_writable($directory)) {
throw new DirectoryException('Directory `logs` is not writable', DirectoryException::DIRECTORY_NOT_WRITABLE);
}
if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) {
throw new FileException('System can't open log file');
}
fputs($file, date("[H:i:s]") . " donen");
fclose($file);
} catch (DirectoryException $e) {
echo "С директорией возникла проблема: ". $e->getMessage();
} catch (FileException $e) {
echo "С файлом возникла проблема: ". $e->getMessage();
} catch (FileSystemException $e) {
echo "Ошибка файловой системы: ". $e->getMessage();
} catch (Exception $e) {
echo "Ошибка сервера: ". $e->getMessage();
}
Важно помнить, что Exception — это прежде всего исключительное событие, иными словами исключение из правил. Не нужно использовать их для обработки очевидных ошибок, к примеру, для валидации введённых пользователем данных (хотя тут не всё так однозначно). При этом обработчик исключений должен быть написан в том месте, где он будет способен его обработать. К примеру, обработчик для исключений вызванных недоступностью файла для записи должен быть в методе, который отвечает за выбор файла или методе его вызывающем, для того что бы он имел возможность выбрать другой файл или другую директорию.
Так, а что будет если не поймать исключение? Вы получите «Fatal Error: Uncaught exception …». Неприятно.
Чтобы избежать подобной ситуации следует использовать функцию set_exception_handler() и установить обработчик для исключений, которые брошены вне блока try-catch и не были обработаны. После вызова такого обработчика выполнение скрипта будет остановлено:
// в качестве обработчика событий
// будем использовать анонимную функцию
set_exception_handler(function($exception) {
/** @var Exception $exception */
echo $exception->getMessage(), "<br/>n";
echo $exception->getFile(), ':', $exception->getLine(), "<br/>n";
echo $exception->getTraceAsString(), "<br/>n";
});
Ещё расскажу про конструкцию с использованием блока finally
— этот блок будет выполнен вне зависимости от того, было выброшено исключение или нет:
try {
// код который может выбросить исключение
} catch (Exception $e) {
// код который может обработать исключение
// если конечно оно появится
} finally {
// код, который будет выполнен при любом раскладе
}
Для понимания того, что это нам даёт приведу следующий пример использования блока finally
:
try {
// где-то глубоко внутри кода
// соединение с базой данных
$handler = mysqli_connect('localhost', 'root', '', 'test');
try {
// при работе с БД возникла исключительная ситуация
// ...
throw new Exception('DB error');
} catch (Exception $e) {
// исключение поймали, обработали на своём уровне
// и должны его пробросить вверх, для дальнейшей обработки
throw new Exception('Catch exception', 0, $e);
} finally {
// но, соединение с БД необходимо закрыть
// будем делать это в блоке finally
mysqli_close($handler);
}
// этот код не будет выполнен, если произойдёт исключение в коде выше
echo "Ok";
} catch (Exception $e) {
// ловим исключение, и выводим текст
echo $e->getMessage();
echo "<br/>";
// выводим информацию о первоначальном исключении
echo $e->getPrevious()->getMessage();
}
Т.е. запомните — блок finally
будет выполнен даже в том случае, если вы в блоке catch
пробрасываете исключение выше (собственно именно так он и задумывался).
Для вводной статьи информации в самый раз, кто жаждет ещё подробностей, то вы их найдёте в статье Исключительный код
Задание
Написать свой обработчик исключений, с выводом текста файла где произошла ошибка, и всё это с подсветкой синтаксиса, так же не забудьте вывести trace в читаемом виде. Для ориентира — посмотрите как это круто выглядит у whoops.
PHP7 — всё не так, как было раньше
Так, вот вы сейчас всю информацию выше усвоили и теперь я буду грузить вас нововведениями в PHP7, т.е. я буду рассказывать о том, с чем вы будете сталкиваться работая над современным PHP проектом. Ранее я вам рассказывал и показывал на примерах какой костыль нужно соорудить, чтобы отлавливать критические ошибки, так вот — в PHP7 это решили исправить, но? как обычно? завязались на обратную совместимость кода, и получили хоть и универсальное решение, но оно далеко от идеала. А теперь по пунктам об изменениях:
- при возникновении фатальных ошибок типа
E_ERROR
или фатальных ошибок с возможностью обработкиE_RECOVERABLE_ERROR
PHP выбрасывает исключение - эти исключения не наследуют класс Exception (помните я говорил об обратной совместимости, это всё ради неё)
- эти исключения наследуют класс Error
- оба класса Exception и Error реализуют интерфейс Throwable
- вы не можете реализовать интерфейс Throwable в своём коде
Интерфейс Throwable
практически полностью повторяет нам Exception
:
interface Throwable
{
public function getMessage(): string;
public function getCode(): int;
public function getFile(): string;
public function getLine(): int;
public function getTrace(): array;
public function getTraceAsString(): string;
public function getPrevious(): Throwable;
public function __toString(): string;
}
Сложно? Теперь на примерах, возьмём те, что были выше и слегка модернизируем:
try {
// файл, который вызывает ошибку парсера
include 'e_parse_include.php';
} catch (Error $e) {
var_dump($e);
}
В результате ошибку поймаем и выведем:
object(ParseError)#1 (7) {
["message":protected] => string(48) "syntax error, unexpected 'будет' (T_STRING)"
["string":"Error":private] => string(0) ""
["code":protected] => int(0)
["file":protected] => string(49) "/www/education/error/e_parse_include.php"
["line":protected] => int(4)
["trace":"Error":private] => array(0) { }
["previous":"Error":private] => NULL
}
Как видите — поймали исключение ParseError, которое является наследником исключения Error
, который реализует интерфейс Throwable
, в доме который построил Джек. Ещё есть множество других исключений, но не буду мучать — для наглядности приведу иерархию исключений:
interface Throwable
|- Exception implements Throwable
| |- ErrorException extends Exception
| |- ... extends Exception
| `- ... extends Exception
`- Error implements Throwable
|- TypeError extends Error
|- ParseError extends Error
|- ArithmeticError extends Error
| `- DivisionByZeroError extends ArithmeticError
`- AssertionError extends Error
И чуть-чуть деталей:
TypeError — для ошибок, когда тип аргументов функции не совпадает с передаваемым типом:
try {
(function(int $one, int $two) {
return;
})('one', 'two');
} catch (TypeError $e) {
echo $e->getMessage();
}
ArithmeticError — могут возникнуть при математических операциях, к примеру когда результат вычисления превышает лимит выделенный для целого числа:
try {
1 << -1;
} catch (ArithmeticError $e) {
echo $e->getMessage();
}
DivisionByZeroError — ошибка деления на ноль:
try {
1 / 0;
} catch (ArithmeticError $e) {
echo $e->getMessage();
}
AssertionError — редкий зверь, появляется когда условие заданное в assert() не выполняется:
ini_set('zend.assertions', 1);
ini_set('assert.exception', 1);
try {
assert(1 === 0);
} catch (AssertionError $e) {
echo $e->getMessage();
}
При настройках production-серверов, директивы
zend.assertions
иassert.exception
отключают, и это правильно
Полный список предопределённых исключений вы найдёте в официальном мануале, там же иерархия SPL исключений.
Задание
Написать универсальный обработчик ошибок для PHP7, который будет отлавливать все возможные исключения.
При написании данного раздела были использованы материалы из статьи Throwable Exceptions and Errors in PHP 7.
Единообразие
— Там ошибки, тут исключения, а можно это всё как-то до кучи сгрести?
Да запросто, у нас же есть set_error_handler()
и никто нам не запретит внутри оного обработчика бросить исключение:
// Бросаем исключение вместо ошибок
function errorHandler($severity, $message, $file = null, $line = null)
{
// Кроме случаев, когда мы подавляем ошибки с помощью @
if (error_reporting() === 0) {
return false;
}
throw new ErrorException($message, 0, $severity, $file, $line);
}
// Будем обрабатывать все-все ошибки
set_error_handler('errorHandler', E_ALL);
Но данный подход с PHP7 избыточен, со всем теперь справляется Throwable
:
try {
/** ... **/
} catch (Throwable $e) {
// отображение любых ошибок и исключений
echo $e->getMessage();
}
Отладка
Иногда, для отладки кода, нужно отследить что происходило с переменной или объектом на определённом этапе, для этих целей есть функция debug_backtrace() и debug_print_backtrace() которые вернут историю вызовов функций/методов в обратном порядке:
<?php
function example() {
echo '<pre>';
debug_print_backtrace();
echo '</pre>';
}
class ExampleClass {
public static function method () {
example();
}
}
ExampleClass::method();
В результате выполнения функции debug_print_backtrace()
будет выведен список вызовов приведших нас к данной точке:
#0 example() called at [/www/education/error/backtrace.php:10]
#1 ExampleClass::method() called at [/www/education/error/backtrace.php:14]
Проверить код на наличие синтаксических ошибок можно с помощью функции php_check_syntax() или же команды php -l [путь к файлу]
, но я не встречал использования оных.
Assert
Отдельно хочу рассказать о таком экзотическом звере как assert() в PHP. Собственно, этот кусочек можно рассматривать как мимикрию под контрактную методологию программирования, и дальше я расскажу вам как я никогда его не использовал
Функция
assert()
поменяла своё поведение при переходе от версии 5.6 к 7.0, и ещё сильней всё поменялось в версии 7.2, так что внимательней читайте changelog’и PHP![]()
Первый случай — это когда вам надо написать TODO прямо в коде, да так, чтобы точно не забыть реализовать заданный функционал:
// включаем asserts в php.ini
// zend.assertions=1
assert(false, "Remove it!");
В результате выполнения данного кода получим E_WARNING
:
Warning: assert(): Remove it! failed
PHP7 можно переключить в режим exception, и вместо ошибки будет всегда появляться исключение AssertionError
:
// переключаем в режим «исключений»
ini_set('assert.exception', 1);
assert(false, "Remove it!");
В результате ожидаемо получаем исключение AssertionError
.
При необходимости, можно выбрасывать произвольное исключение:
assert(false, new Exception("Remove it!"));
Я бы рекомендовал использовать метки
@TODO
, современные IDE отлично с ними работают, и вам не нужно будет прикладывать дополнительные усилия и ресурсы для работы с ними, хотя с ними велик соблазн «забить»
Второй вариант использования — это создание некоего подобия TDD, но помните — это лишь подобие. Хотя, если сильно постараться, то можно получить забавный результат, который поможет в тестировании вашего кода:
// callback-функция для вывода информации в браузер
function backlog($script, $line, $code, $message) {
echo $message;
}
// устанавливаем callback-функцию
assert_options(ASSERT_CALLBACK, 'backlog');
// отключаем вывод предупреждений
assert_options(ASSERT_WARNING, false);
// пишем проверку и её описание
assert(sqr(4) === 16, 'When I send integer, function should return square of it');
// функция, которую проверяем
function sqr($a) {
return; // она не работает
}
Третий вариант — некое подобие на контрактное программирование, когда вы описали правила использования своей библиотеки, но хотите точно убедится, что вас поняли правильно, и в случае чего сразу указать разработчику на ошибку (я вот даже не уверен, что правильно его понимаю, но пример кода вполне рабочий):
/**
* Настройки соединения должны передаваться в следующем виде
*
* [
* 'host' => 'localhost',
* 'port' => 3306,
* 'name' => 'dbname',
* 'user' => 'root',
* 'pass' => ''
* ]
*
* @param $settings
*/
function setupDb ($settings) {
// проверяем настройки
assert(isset($settings['host']), 'Db `host` is required');
assert(isset($settings['port']) && is_int($settings['port']), 'Db `port` is required, should be integer');
assert(isset($settings['name']), 'Db `name` is required, should be integer');
// соединяем с БД
// ...
}
setupDb(['host' => 'localhost']);
Если вас заинтересовали контракты, то специально для вас у меня есть ссылочка на фреймворк PhpDeal.
Никогда не используйте
assert()
для проверки входных параметров, ведь фактическиassert()
интерпретирует первый параметр (ведёт себя какeval()
), а это чревато PHP-инъекцией. И да, это правильное поведение, ведь если отключить assert’ы, то все передаваемые аргументы будут проигнорированы, а если делать как в примере выше, то код будет выполняться, а внутрь отключенного assert’a будет передан булевый результат выполнения. А, и это поменяли в PHP 7.2![]()
Если у вас есть живой опыт использования assert()
— поделитесь со мной, буду благодарен. И да, вот вам ещё занимательно чтива по этой теме — PHP Assertions, с таким же вопросом в конце
В заключение
Я за вас напишу выводы из данной статьи:
- Ошибкам бой — их не должно быть в вашем коде
- Используйте исключения — работу с ними нужно правильно организовать и будет счастье
- Assert — узнали о них, и хорошо
P.S.
Это репост из серии статей «PHP для начинающих»:
- Сессия
- Подключение файлов
- Обработка ошибок
Если у вас есть замечания по материалу статьи, или возможно по форме, то описывайте в комментариях суть, и мы сделаем данный материал ещё лучше.
Спасибо Максиму Слесаренко за помощь в написании статьи.
Parse error: syntax error, unexpected ‘;’, expecting T_CATCH
Discussion in ‘PHP’ started by mark103, Sep 23, 2010.
-
mark103
Active Member- Messages:
- 110
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 53
#1
Hi guys,
I have a problem with the script. There is a parse error in line 7 which it end of the line. I need your help to make them get correct, as I am not a programmer and know very little PHP.
Here it is the code:
<?php try { include_once('HideUrlConfig.php'); } ?>
Parse error: syntax error, unexpected $end, expecting T_CATCH in /home/username/public_html/mysite.com/myscript.php on line 6
What do I needs to change it with?
-
guardian999
Active Member- Messages:
- 376
- Likes Received:
- 1
- Best Answers:
- 0
- Trophy Points:
- 53
#2
<?php try { include_once('HideUrlConfig.php'); }catch(Exception $E){} ?>
You need add exception
-
mark103
Active Member- Messages:
- 110
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 53
#3
Thanks guardian999, so I want to add the error message in the catch exception that if the server is gone down?
I want to add the error message which something is like «the server is down at the moment, please try again later»
Thanks,
Mark -
Internet Monk
Peon- Messages:
- 16
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 0
#4
try { include_once('HideUrlConfig.php'); } catch (Exception $e) { echo "The server is down. Please try again later .."; }
-
mark103
Active Member- Messages:
- 110
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 53
#5
Thanks Internet Monk, so how could I get rid of the 404 not found that says in the webpage:
I only wants to display the message by the catch expection:Here it is the source code:
<?php try { $homepage = file_get_contents('http://www.myanothersite.com/script1.php'); echo $homepage; }catch(Exception $E){} echo "The server is down. Please try again later .."; ?>
-
Internet Monk
Peon- Messages:
- 16
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 0
#6
if ($homepage = @file_get_contents("http://www.domain.com")) { echo $homepage; } else { echo "The server is down. Please try again later .."; }
-
mark103
Active Member- Messages:
- 110
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 53
#7
Thanks, but it still showing the message like below…
So I only want to display the message without «Not FoundThe requested URL /script1.php was not found on this server.
Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.»
Which I means that I only want to displaying the message:
Here it is the update php that I am using:
<?php if ($homepage = @file_get_contents("http://www.mysite.com/script1.php")) { echo $homepage; } else { echo "The server is down. Please try again later .."; } ?>
Any idea?
-
mark103
Active Member- Messages:
- 110
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 53
-
daljit
Active Member- Messages:
- 312
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 51
#9
i dont sure this will work but some time i also have a problem like this. if your editor is not high lighted the syntax because of space between <?php ?> tags.So write the code like this
<?php
try
{
include_once(‘HideUrlConfig.php’);
}
?>
i hope this will work for you -
sunlcik
Peon- Messages:
- 39
- Likes Received:
- 0
- Best Answers:
- 0
- Trophy Points:
- 0
#10
Paste your HideUrlConfig.php code pls.
-
xrvel
Notable Member- Messages:
- 918
- Likes Received:
- 30
- Best Answers:
- 2
- Trophy Points:
- 225
#11
Use curl. It’s a swiss-army-knife
<?php if (!function_exists('curl_init')) { echo 'Curl is not enabled.'; exit(); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://localhost/test.php'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_AUTOREFERER, true); curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); curl_setopt($ch, CURLOPT_TIMEOUT, 94); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 94); $res = curl_exec($ch); $info = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // HTTP Code checking if ($info == 200) { echo 'Everything is fine.'; echo $res;// this is the URL content } else if ($info == 404) { echo 'The server is down. Please try again later ..'; } else { echo 'The server has '.$info.' error. Please try again later ..'; } ?>
Laravel Syntax Error, Unexpected ‘catch’ (t_catch) |
View Content |
I am new to the Laravel Framework, doing an internship and at the very end.. I need some assistance please with some try catch error, Its supposed to throw an error if the site name is already in the database.. If someone could help me please and thank you ..
«`
public function create()
{
return View::make(‘edit.create’);
}
public function edit( $clientsite )
{
return View::make(‘edit.edit’, compact(‘clientsite’));
}
public function saveCreate()
{
$input = Input::all();
try
{
$clientsite = new ClientSite;
$clientsite->siteName = $input[‘siteName’];
$clientsite->description = $input[‘description’];
$clientsite->launchDate = $input[‘launchDate’];
$clientsite->save();
//ClientSite::whereSiteName($clientsite->siteName)->first();
ClientSite::where(‘siteName’, $clientsite->siteName)->first();
$clientID = $clientsite[‘clientID’];//getting clientID for use in join query
//queries for retrieving features of each group for the selected client
$clientFeatures = DB::table(‘features’)->join(‘clientFeatures’, function($join) use($clientID)
{
$join->on( ‘clientFeatures.featureID’, ‘=’, ‘features.featureID’)
->where(‘clientFeatures.clientID’, ‘=’, $clientID);
})->get();
$groupIDs = array();
foreach ($clientFeatures as $c) {
$groupIDs[] = $c->groupID;
}
catch(IlluminateDatabaseQueryException $e)
{
return View::make(‘profiles.clientProfiles’)->with(‘clientsite’,$clientsite)
->with(‘groupIDs’,$groupIDs)
->with(‘clientFeatures’,$clientFeatures)
->with(‘status’,'<strong>’.$siteName.’ Site already exist!</strong>’);
;
}
«`
https://github.com/webdevdea/MyDyn ( i have not pushed these changes because I have an error )
Similar Tutorials
Hi guys,
I have a problem with the script. There is a parse error in line 7 which it end of the line. I need your help to make them get correct, as I am not a programmer and know very little PHP.
Here it is the code:
<?php
try
{
include_once(‘HideUrlConfig.php’);
}
?>
Parse error: syntax error, unexpected $end, expecting T_CATCH in /home/username/public_html/mysite.com/myscript.php on line 6
What do I needs to change it with?
Parse error: syntax error, unexpected T_STRING in C:xampphtdocsmyworkunique.php on line 15
<html>
<head>
<title>
</title>
</head>
<body bgproperties=»fixed»>
<?php
$dbhost = ‘localhost’;
$dbuser = ‘root’;
$dbpass = »;
$con = mysql_connect($dbhost, $dbuser, $dbpass) or die (‘Error connecting to mysql’);
$dbname = ‘mywork’;
mysql_select_db($dbname, $con);
$sql=mysql_query(insert into users (regno,name,gender,date,month,year,emailid,cell,paddress,caddress,incometype,incomeamt,dad,fyes,dadocup,mom,myes,momocup,password) VALUES (‘$_POST[regno]’,’$_POST[name]’,’$_POST[gender]’,’$_POST[date]’,’$_POST[month]’,’$_POST[year]’,’$_POST[emailid]’,’$_POST[cell]’,’$_POST[paddress]’,’$_POST[caddress]’,’$_POST[incometype]’,’$_POST[incomeamt]’,’$_POST[dad]’,’$_POST[fyes]’,’$_POST[dadocup]’,’$_POST[mom]’,’$_POST[myes]’,’$_POST[momocup]’,’$_POST[password]’)»);
$sql1=mysql_fetch_array($sql);
$result = @mysql_query($SQl1);
$result=»SELECT * FROM users WHERE regno=’$regno'»;
while($row = mysql_fetch_array($result))
{
//echo $row[‘regno’].»regno<br>»;
//echo $row[‘name’].»name<br>»;
//echo $row[‘gender’].»gender<br>»;
//echo $row[‘date’].»date<br>»;
//echo $row[‘month’].»month<br>»;
//echo $row[‘year’].»year<br>»;
//echo $row[’emailid’].»emailid<br>»;
//echo $row[‘cell’].»cell<br>»;
//echo $row[‘paddress’].»paddress<br>»;
//echo $row[‘caddress’].»caddress<br>»;
//echo $row[‘incometype’].»incometype<br>»;
//echo $row[‘incomeamt’].»incomeamt<br>»;
//echo $row[‘dad’].»dad<br>»;
//echo $row[‘fyes’].»fyes<br>»;
//echo $row[‘dadocup’].»dadocup<br>»;
//echo $row[‘mom’].»mom<br>»;
//echo $row[‘myes’].»myes<br>»;
//echo $row[‘momocup’].»momocup<br>»;
//echo $row[‘password’].»password<br>»;
}
echo «Thanks for Register!»;
if (!mysql_query($sql,$con))
{
die(‘Error: ‘ . mysql_error());
}
echo «1 record added»;
mysql_close($con);
?>
<form name=»security» action=»index.php» method=»post»>
<input type=»submit» value=»click here to login»>
</form>
</body>
</html>
Hi folks,
I am a complete n00b at php and mysql. I am teaching myself from books and the WWW, but alas I am stuck…
the error I get is:
Parse error: syntax error, unexpected T_STRING in X:xampphtdocssearch.php on line 7
here is the code:
<?php
mysql_connect («localhost», «user», «password») or die (mysql_error());
mysql_select_db («it_homehelp_test») or die (mysql_error());
$term = $_POST[‘term’];
$sql = $mysql_query(select * from it_homehelp_test where ClientName1 like ‘%term%’); <<<——this is line 7
while ($row = mysql_fetch_array($sql)){
echo ‘Client Name:’ .$row[‘ClientName1’];
echo ‘Address:’ .$row[‘Address1’];
echo ‘Phone:’ .$row[‘Tel1’];
}
?>
Any help you can offer would be great. I can also post the «.html» file that creates the search bar if it is needed.
Thanks
I have been trying to get my files to upload onto a computer and I receive this message: Parse error: syntax error, unexpected T_STRING in /home/content/19/6550319/html/listing.php on line 27. Line 27 is how the php logs into my SQL. The problem is that I was able to log in before. I just made changes to the form by adding a dropdown menu and price and now it says it doesnt parse.
Can anyone figure this out. I will include the code without the login information because the forum is public but I did put the words left out for you to see where I took out the passcodes.
Code: [Select]
<?php
//This is the directory where images will be saved
$target = «potofiles/»;
$target = $target . basename( $_FILES[‘photo’][‘name’]);
//This gets all the other information from the form
$price=$_POST[‘price’];
$gig=$_POST[‘giga’];
$yesg=$_POST[‘yesg’];
$pic=($_FILES[‘photo’][‘name’]);
$pic2=($_FILES[‘phototwo’][‘name’]);
$pic3=($_FILES[‘photothree’][‘name’]);
$pic4=($_FILES[‘photofour’][‘name’]);
$description=$_POST[‘iPadDescription’];
$condition=$_POST[‘condition’];
$fname=$_POST[‘firstName’];
$lname=$_POST[‘lastName’];
$email=$_POST[’email’]
// Connects to your Database
mysql_connect («left out», «left out», «left out») or die(mysql_error()) ;
mysql_select_db(«left out») or die(mysql_error()) ;
//Writes the information to the database
mysql_query(«INSERT INTO listing (price,giga,yesg,photo,phototwo,photothree,photofour,iPadDescription,condition,firstName,lastName,email)
VALUES (‘$price’, ‘$gig’, ‘$yesg’, ‘$pic’, ‘$pic2’, ‘$pic3’, ‘$pic4’, ‘$description’, ‘$condition’, ‘$fname’, ‘$lname’, ‘$email’)») ;
//Writes the photo to the server
if(move_uploaded_file($_FILES[‘photo’][‘tmp_name’], $target))
{
//Tells you if its all ok
echo «The file «. basename( $_FILES[‘uploadedfile’][‘name’]). » has been uploaded, and your information has been added to the directory»;
}
else {
//Gives and error if its not
echo «Sorry, there was a problem uploading your file.»;
}
echo date(«m/d/y : H:i:s», time())
?>
I don`t get it, waht is wrong?!
Code: [Select]
<?php
require_once ‘auth.php’;
if (!isset($_SESSION[‘SESS_VERIFY’])) {
header(«location: access-denied.php»);
exit();
}
if ($_SESSION[‘lang’] == ‘Ro’) {
// setare data romania
date_default_timezone_set(‘Europe/Bucharest’);
$today = getdate();
$zi = $today[‘mday’];
$luna = $today[‘mon’];
$lunastring = $today[‘month’];
$an = $today[‘year’];
$data = $zi.$luna.$an;
$data = (string)$data;
$ora = date(‘H:i:s’);
$msg = array();
$err = array();
$luni = array (
1=>’Ianuarie’,
2=>’Februarie’,
3=>’Martie’,
4=>’Aprilie’,
5=>’Mai’,
6=>’Iunie’,
7=>’Iulie’,
8=>’August’,
9=>’Septembrie’,
10=>’Octobrie’,
11=>’Noiembrie’,
12=>’Decembrie’);
// comun
const SQL_ERR = ‘SQL statement failed with error: ‘;
const ADD_MODEL = ‘ADAUGA UN MODEL NOU’;
.
.many constants..
.
}
elseif ($_SESSION[‘lang’] == ‘It’) {…
Thank you!
I just enabled error reporting and I am not that familiar with it. I know I have an error some where around line 33. I know I am missing a bracket or a comma or some other syntax error I just cannot find where the error is. Below is my script.
Thanks for any help.
Code: [Select]
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN»
«http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
<head>
<title>Airline Survey</title>
<meta http-equiv=»content-type» content=»text/html; charset=iso-8859-1″ />
<meta name=»author» content=»Revised by abc1234″/>
</head>
<body>
<?php
$WaitTime = addslashes($_POST[«wait_time»]);
$Friendliness = addslashes($_POST[«friendliness»]);
$Space = addslashes($_POST[«space»]);
$Comfort = addslashes($_POST[«comfort»]);
$Cleanliness = addslashes($_POST[«cleanliness»]);
$Noise = addslashes($_POST[«noise»]);
if (empty($WaitTime) ||
empty($Friendliness) ||
empty($Space) ||
empty($Comfort) ||
empty($Cleanliness) ||
empty($Noise))
echo «<hr /><p>You must enter a value in each field. Click
your browser’s Back button to return to the form.</p><hr />»;
else {
$Entry = $WaitTime . «n»;
$Entry .= $Friendliness . «n»;
$Entry .= $Space . «n»;
$Entry .= $Comfort . «n»;
$Entry .= $Cleanliness . «n»;
$Entry .= $Noise . «n»;
$SurveyFile = fopen(«survey.txt», «w»)
}
if (flock($SurveyFile, LOCK_EX)) {
if (fwrite($SurveyFile, $Entry) > 0) {
echo «<p>The entry has been successfully added.</p>»;
flock($SurveyFile, LOCK_UN;
fclose($SurveyFile);
else
echo «<p>The entry could not be saved!</p>»;
}
else
echo «<p>The entry could not be saved!</p>»;
}
?d>
<p><a href=»AirlineSurvey.html»>Return to Airline Survey</a></p>
</body>
</html>
Hello everyone,
I am a total newbie in PHP and so do here. I am trying to build a table consisting foreign key and primary key and it is showing error like «Parse error: syntax error, unexpected ‘cities’ (T_STRING) in line number 29». I have marked up my lines according to sublime text 3 editor. I am trying to create a database.
1 <?php
2 $servername = «localhost»;
3 $username = «username»;
4 $password = «password»;
5 $dbname = «newDB»;
7 // Create connection
8 $conn = new mysqli($servername, $username, $password, $dbname);
10 // Check connection
11 if ($conn->connect_error) {
12 die(«Connection failed: » . $conn->connect_error);}
14 $firstname = $conn->real_escape_string($_REQUEST[‘firstname’]);
15 $lastname = $conn->real_escape_string($_REQUEST[‘lastname’]);
16 $address = $conn->real_escape_string($_REQUEST[‘address’]);
17 $city = $conn->real_escape_string($_REQUEST[‘city’]);
18 $country = $conn->real_escape_string($_REQUEST[‘country’]);
19 $phone_number = $conn->real_escape_string($_REQUEST[‘phone_number’]);
20 $email = $conn->real_escape_string($_REQUEST[’email’]);
22 // Attempt insert query execution
23 $sql1 = «INSERT INTO cities VALUES (‘$city’)»;
25 $sql2 = «INSERT INTO countries VALUES (‘$country’)»;
27 $sql3 = «INSERT INTO Contacts (firstname, lastname, address, city, country, phone, email) VALUES (‘$firstname’, ‘$lastname’, ‘$address’, $city, $country, ‘$phone_number’,’$email’)»;
29 SELECT * FROM cities;
SELECT * FROM countries;
SELECT * FROM Contacts;
if($conn->query($sql1) === true){
echo «City added successfully.»;
} else{
echo «ERROR: Could not able to execute » . $conn->error;
}
if($conn->query($sql2) === true){
echo «Çountry added successfully.»;
} else{
echo «ERROR: Could not able to execute » . $conn->error;
}
if($conn->query($sql3) === true){
echo «Çontact added successfully.»;
} else{
echo «ERROR: Could not able to execute » . $conn->error;
}
// Close connection
$conn->close();
?>
i keep getting the above error.. help this is a class of the log entry
<?php
require_once «config.php»;
abstract class DataObject {
protected $data = array();
public function__construct( $data ) {
foreach ( $data as $key => $value ) {
if ( array_key_exists( $key, $this->data )) $this->data[$key] =
$value;
}
}
public function getValue( $field ) {
if ( array_key_exists( $field, $this->data )) {
return $this->data[$field];
} else {
die( «field not found» );
}
}
public function getValueEncoded( $field ) {
return htmlspecialchars( $this->getValue( $field ));
}
protected function connect() {
try {
$conn = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD );
$Conn->setAttribute( PDO::ATTR_PERSISTENT, true );
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
} catch ( PDOException $e->getMessage() );
die( «connection failed: » . $e->getMessage() );
}
return $conn;
}
protected function disconnect( $conn ) {
$conn = «»;
}
}
?>
sorry this was the actuall php code for this error…
<?php
require_once «DataObject.class.php»;
class LogEntry extends DataObject {
protected $data = array(
«userid» => «»,
«pageUrl» => «»,
«numVisits» => «»,
«lastAcces» => «»,
);
public static function getLogEntries( $userid ) {
$conn = parent::connect();
$sql = «SELECT * FROM » . TBL_accesslog . » WHERE userid = : userid
ORDER BY lastAcces DESC»;
try {
$st = conn->prepare( $sql );
$st->bindValue( «:userid», $userid, PDO::PARAM_INT );
$st->execute();
$logEntries = array();
foreach ( $st->fetchAll() as $row ) {
$logEntries[] = new logEntry( $row);
}
parent::disconnect( $conn );
return $logEntries;
} catch ( PDOExeception $e ) {
parent::disconnect( $conn );
die( «Query failed: » . $e->getMessage() );
}
}
}
?>
Hey Everyone,
I’m getting this error when I submit my contact form.
Parse error: syntax error, unexpected $end in /home1/user/public_html/contact/process.php on line 22
I got this code from a video on youtube. http://www.youtube.com/watch?v=rdsz9Ie6h7I
If I made a mistake or TYPO please let me know. Thanks!
Here’s my code:
<?php
$emailSubject = ‘Contact Form Submission’;
$sendto = ‘info@mydomain.com’;
$nameField = $_Post[‘name’];
$emilField = $_Post[’email’];
$phoneField = $_Post[‘phone’];
$SubjectField = $_Post[‘subject’];
$messageField = $_Post[‘message’];
$body = <<<EOD
<br><hl><br>This Form was submitted from the Domain.com contact page.<br>
Name: $name<br>
E-Mail: $email<br>
Phone: $phone<br>
Subject: $subject<br>
Message: $message<br>
BOD;
$headers = «FROM: $emailrn»;
$headers .=»Content-Type: text/htmlrn»;
$success = mail($sendto, $emailSubject, $body, $headers);
?>
SET UP: Windows vista
# XAMPP 1.7.3,
# Apache 2.2.14 (IPv6 enabled) + OpenSSL 0.9.8l
# MySQL 5.1.41 + PBXT engine
# PHP 5.3.1
# phpMyAdmin
After entering various different information from previous forms on different pages I finally get this error message «Parse error: syntax error, unexpected T_STRING in C:blablah on line 31» on the following code:
<?php
//let’s start our session, so we have access to stored data
session_start();
include ‘db.inc.php’;
$db = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD) or
die (‘Unable to connect. Check your connection parameters.’);
mysql_select_db(MYSQL_DB, $db) or die(mysql_error($db));
//let’s create the query
$query = ‘INSERT INTO subscriptions (name, email_address, membership_type, terms_and_conditions,
name_on_card,
credit_card_number, credit_card_expiration_data)
VALUES (
«‘ . $_SESSION[$name, $db] . ‘»,
‘ . $_SESSION[$email_address, $db] . ‘»,
‘ . $_SESSION[$membership_type, $db] . ‘»,
‘ . $_SESSION[$terms_and_conditions, $db] . ‘»,
‘ . $_POST[$name_on_card, $db] . ‘»,
‘ . $_POST[$credit_card_number, $db] . ‘»,
‘ . $_POST[$credit_card_expiration, $db] . ‘)’;
if (isset($query)) {
$result = mysql_query($query, $db) or die(mysql_error($db));
}
?>
<p>Done!</p>
</body>
</html>
?>
Any help would be appreciated. I’m practicing this with the ambition to develop a multi-page registration using sessions for a website so even web pages that might help me with this aim would be good.
I keep getting an error code when running my php, it states:
Parse error: syntax error, unexpected $end in W:wwwbloglogin.php on line 33
Line 33 is </html>
Code: [Select]
<?php
mysql_connect («localhost», «root», «»);
mysql_select_db(«blog»);
?>
<html>
<head>
<title>Login</title>
</head>
<body>
<?php
if(isset($_POST[‘submit’])){
$name = $_POST[‘name’];
$pass = $_POST[‘password’];
$result = mysql_query(«SELECT * FROM users WHERE name=’$name’ AND pass=’$pass'»);
$num = mysql_num_rows($result);
if($num == 0){
echo «Bad login, go <a href=’login.php’>back</a>»;
}else{
session_start();
$SESSION [‘name’] = $name;
header(«Location: admin.php»);
}
?>
<form action=’login.php’ method=’post’>
Username: <input type=’text’ name=’name’ /><br />
Password: <input type=’password’ name=’password’ /><br />
<input type=’submit’ name=’sumbit’ value=’Login!’ />
</form>
</body>
</html>Can any one advise me whats wrong?
This topic has been moved to PHP Applications.
http://www.phpfreaks.com/forums/index.php?topic=344105.0
I have been getting that error and I cannot figure out why it is happening
Here is the error: Parse error: syntax error, unexpected T_ENDWHILE, expecting ‘,’ or ‘;’ in /home/scswc188/public_html/index.php on line 23
Here is my Code (Database Credentials removed for obvious reasons)
<?PHP
// Conect to the Mysql Server
$connect = mysql_connect(«IP»,»USER»,»PASS»);
//connect to the database
mysql_select_db(«TABLE»);
//query the database
$query = mysql_query(«SELECT * FROM users_online WHERE online = 1»);
// fetch the results / convert into an array
WHILE($rows = mysql_fetch_array($query)):
$users = $rows[‘name’];
echo «‘<font color=’black’>Online:<font color=’green’>$users, </font></font>;»
endwhile;
?>
or here http://pastebin.com/ZYh4t2pD
Thanks
Edit: Found the php tag
Code: [Select]
<?php
if (!isset($_POST[‘submit’])) {
?>
<h2>Todays Special</h2>
<p>
<form action=»<?php echo $_SERVER[‘PHP_SELF’]; ?>» method=»post»>
<select name=»day»>
<option value=»1″>Monday/Wednesday
<option value=»2″>Tuesday/Thursday
<option value=»3″>Friday/Sunday
<option value=»4″>Saturday
</select>
input type=»submit» name=»submit» value=»Go»>
</form>
<?php
// get form selection
$day = $_POST[‘day’];
// check value and select appropriate item
switch ($day) {
case 1:
$special = ‘Chicken in oyster sauce’;
break;
case 2:
$special = ‘French onion soup’;
break;
case 3:
$special = ‘Pork chops with mashed potatoes and green salad’;
break;
default:
$special = ‘Fish and chips’;
break;
}
?>
Hi all,
Does anybody can help me with this error…?
I am trying create a simple form which insert data into mysql table called ‘sample’
Here is my code…
Code: [Select]
<?php
$connection = mysql_connect(«localhost»,»root», «123»);
if(!$connection)
{
die(«db connection error» .mysql_error());
}
$db_select = mysql_select_db(«project», $connection);
if(!$db_select)
{
die(«db select error» .mysql_error());
}
$sql = «INSERT INTO sample (id,firstname,lastname,bio,gender)
VALUES (‘$_POST[‘ID_’]’,’$_POST[‘firstname’]’,’$_POST[‘lastname’]’,’$_POST[‘bio’]’,’$_POST[‘gender’]’)»;
if(!$sql)
{
die(‘Error: ‘ . mysql_error());
}
echo «1 record added»;
?>
And every time I am getting this annoying error
Quote
Parse error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or T_NUM_STRING in C:wampwwwprojectprocess.php on line 19
and Line 19 is Code: [Select]
(‘$_POST[‘ID_’]’,’$_POST[‘firstname’]’,’$_POST[‘lastname’]’,’$_POST[‘bio’]’,’$_POST[‘gender’]’)»;
Thanks in advance..!
PHP is the language used to build websites on the internet for over ten years. Although, there are a lot of people who think that it’s time to move into something else, PHP is a dynamic programming language, which means that it can be adapted to the current needs. And the PHP Core team has been excellent in bringing out new features that make PHP an attractive language in this time and age.
The flexibility in the PHP language makes it easy to handle things like exceptions in code, which are the out of the ordinary scenarios that can occur. They can be caused by some unexpected input, a bug, or some other problem. PHP 8 is a new version of this language that was released on 26 November 2020. The new version has been adapted to be more secure and handle exceptions better than the previous versions.
Potential exceptions/errors are enclosed inside a try block if exception is encountered, will be thrown to catch or finally block. PHP usually handles exceptions in a separate catch block for each different type of exception.
In this post, you can gain knowledge about what exactly is exception handling, and how it works.
Below are the topics that shall be covered in this blog:
- When, Where, and How to use Exceptions and Errors in PHP?
-
Error Class
-
Exception Class
-
Custom Exception
-
Multiple Exception
-
Global Exception Handler
-
Non-Capturing Catches
#1 When, Where, and How to use Exceptions and Errors in PHP?
PHP 7 introduced the new Throwable interface to unite the exception branches Exception and Error. The entire PHP exception hierarchy is as follows:
interface Throwable
|- Error implements Throwable
|- CompileError extends Error
|- ParseError extends CompileError
|- TypeError extends Error
|- ArgumentCountError extends TypeError
|- ArithmeticError extends Error
|- DivisionByZeroError extends ArithmeticError
|- AssertionError extends Error
|- Exception implements Throwable
|- ClosedGeneratorException
|- DOMException
|- ErrorException
|- IntlException
|- LogicException
|- BadFunctionCallException
|- BadMethodCallException
|- DomainException
|- InvalidArgumentException
|- LengthException
|- OutOfRangeException
|- PharExceptionaddition
|- ReflectionException
|- RuntimeException
|- mysqli_sql_exception
|- OutOfBoundsException
|- OverflowException
|- PDOException
|- RangeException
|- UnderflowException
|- UnexpectedValueException
|- Custom Exception
To catch both exceptions and errors in PHP 8, add a catch block for Exception after catching Throwable
first.
try
{
// Code that may throw an Exception or Error.
} catch (Throwable $t)
{
// Executed only in PHP 7 and more
}
#2 Error Class
Error Class is the base class for all internal PHP errors. Errors can be caught in try/catch block as explained above. Few errors will throw a specific subclass of Error such as Parse Error, Type Error, and so on.
Here are the list of various types of errors (we have covered only the most common ones):
- Parse/Syntax Error
-
Type Error
- Arithmetic Error
-
Assertion Error
-
Value Error
a. Parse/Syntax Error
A syntax/parse error in the code while compilation, a Parse error is thrown. If a code contains an error, the PHP parser cannot interpret the code and it stops working.
Let’s look into a simple example for understanding Parse error.
Code:
<?php
$x = "Exception";
y = "Handling";
echo $x . ' ' . y;
?>
Output:
syntax error, unexpected '=' in line 3
b. Type Error
When data type mismatch happens in PHP while doing an operation, a Type error is thrown. There are three scenarios where this type of error is thrown:
- Invalid number of arguments passed to a built-in function.
- Value returned from a function doesn’t match the declared function return type.
- Argument type passed to a function doesn’t match the declared parameter type.
Let’s look into a simple example for understanding Type error.
Code:
<?php
function add(int $x, int $y)
{
return $x + $y;
}
try {
$value = add('Type', 10);
}
catch (TypeError $e) {
echo $e->getMessage(), "n";
}
?>
Output:
Argument 1 passed to add() must be of the type integer, string given.
c. Arithmetic Error
Occurrence of error while performing a mathematical operation, bit shifting by a negative number or calling an intdiv() function, the Arithmetic error is thrown.
Example With Division Operator:
<?php
try {
intdiv(PHP_INT_MIN, -1);
}
catch (ArithmeticError $e) {
echo $e->getMessage();
}
?>
Output:
Division of PHP_INT_MIN by -1 is not an integer
Example With Modulo Operator:
<?php
try {
$x = 4;
$y = 0;
$result = $x%$y;
}
catch (DivisionByZeroError $e) {
echo $e->getMessage();
}
?>
Output:
Modulo by zero error
Example With Division Operator Which Returns INF:
<?php
try {
$x = 4;
$y = 0;
$result = $x / $y;
}
catch (DivisionByZeroError $e) {
echo $e->getMessage();
}
?>
Output:
INF
Explanation:
There is a very minute difference in the above two examples. The first one contains the Modulo operator
and the second one has the Division operator
. If any variable divided by zero will return an error, Division by zero error
. When any variable divided by zero with modulo operator returns Modulo by zero error
and the variable divided by zero with the division operator also returns anyone the following- INF, NAN, -INF
d. Assertion Error
When an assert() call fails or let’s say when the condition inside the assert() call doesn’t meet, the Assertion error is thrown. String description emits E_DEPRECATED message from PHP 7.2 version. The Assertion Error thrown by assert() will be sent to catch block only if assert.exception=on is enabled in php.ini.
Let’s look into a simple example for understanding assertion error.
Code:
<?php
try {
$x = 1;
$y = 2;
$result = assert($x === $y);
if (!$result) {
throw new DivisionByZeroError('Assertion error');
}
}
catch (AssertionError $e) {
echo $e->getMessage();
}
?>
Output:
Assertion error
e. Value Error
When the type of the argument is correct and the value of it is incorrect, a value error is thrown. These type of errors occurs when:
- Passing a negative value when the function expects a positive value.
- Passing an empty string or array when function expects a non-empty string/array.
Let’s look into a simple examples for understanding value error.
Code:
<?php
$x = strpos("u", "austin", 24);
var_dump($x);
?>
Output:
[Mon Feb 22 20:59:04 2021]
PHP Warning: strpos(): Offset not contained in string in /home/ubuntu/value_error.php on line 2
Code:
<?php
$x = array_rand(array(), 0);
var_dump($x);
?>
[Mon Feb 22 21:04:14 2021] PHP Warning: array_rand(): Array is empty in /home/ubuntu/index.php on line 2
#3 Exception Class
Exception Class occurs when a specified/exceptional error condition changes the normal flow of the code execution.
Exception handling comprises five components i.e, try block, exception, throw, catch block, and finally block.
Let’s look into a simple example for understanding the above-mentioned components
Code:
<?php
function add($x,$y) {
if (is_numeric($x) == False) {
throw new Exception('Num1 is not a number');
}
if (is_numeric($y) == False) {
throw new RuntimeException('Num2 is not a number');
}
return $x + $y;
}
try {
echo add(5,10). "n";
echo add(5,k). "n";
}
catch (Exception $e) {
echo 'Exception caught: ', $e->getMessage(), "n";
}
finally {
echo "Finally Block.n";
}
// Continue execution
echo "Hello Worldn";
?>
Output:
15
Exception caught: Num2 is not a number
Finally Block.
Hello World
Explanation:
Our example is about adding two numbers and we assumed that we might get non-numeric value as input which would raise an error.
-
We created a function called addition with Exception for non-numeric values and If encountered with the exception, will throw it with the exception message.
-
We called the addition function inside a Try block so that non-numeric value error won’t affect/stop the whole execution. All potential exceptions should be enclosed inside a try block.
-
The Catch block will receive any exceptions thrown from the try block and execute the code inside the block. In our case will print the error message ‘Caught exception: Num2 is not a number’.
-
The Finally block will be executed irrespective of whether we received exception or not.
#4 Custom Exception
We use custom exception to make it clear what is being caught in the catch block and to understand the exception in a better way. The custom exception class inherits properties from the PHP exception’s class where you can add your custom functions too. To easily understand the exceptions we can use custom exceptions and can log it for the future use.
If you just want to capture a message, you can do it at follows:
try {
throw new Exception("This is an error message");
}
catch(Exception $e) {
print $e->getMessage();
}
If you want to capture specific error messages which could be easy to understand you can use:
try {
throw new MyException("Error message");
}
catch(MyException $e) {
print "Exception caught: ".$e->getMessage();
}
catch(Exception $e) {
print "Error: ".$e->getMessage();
}
Code:
<?php
class customStringException extends Exception
{
public function myerrorMessage()
{
//error message
$errorMsg = 'Error on line ' . $this->getLine() . ': <b>' . $this->getMessage() . '</b> is not a String';
return $errorMsg;
}
}
class customNumericException extends Exception
{
public function myerrorMessage()
{
//error message
$errorMsg = 'Error on line ' . $this->getLine() . ': <b>' . $this->getMessage() . '</b> is not an Integer';
return $errorMsg;
}
}
function typeCheck($name, $age)
{
if (!is_string($name)) {
throw new customStringException($name);
}
if (!is_numeric($age)) {
throw new customNumericException($age);
} else {
echo $name . " is of age " . $age;
}
}
try {
echo typeCheck("Sara", 25) . "n";
echo typeCheck(5, 10) . "n";
}
catch (customStringException $e) {
echo $e->myerrorMessage();
}
catch (customNumericException $e) {
echo $e->myerrorMessage();
}
?>
Output:
Sara is of age 25
Error on line 21: 5 is not a String
Explanation:
The above example is on a type check, we have two variables name and age . Let’s assume $name is of type string and $age is of type integer and we assumed that we might get any type of value as input which would raise an error.
-
We created a function called typeCheck to check the type of the variable with exception. If the condition fails it will throw an exception with an Exception message that we have customized.
-
We created a class
customStringException
to create a custom exception handler with a function callederrorMessage
which would be called when an exception occurs. -
Here we called the typeCheck function inside a try block so that if any error is encountered it could be caught in the catch block.
#5 Multiple Exception
You can also handle multiple exception in a single catch block using the pipe ‘|’ symbol like this:
try {
$error = "Foo / Bar / Baz Exception"; throw new MyBazException($error);
}
catch(MyFooException | MyBarException | MyBazException $e) {
//Do something here
}
#6 Global Exception Handler
In Global Exception Handler, it sets the default exception handler if an exception is not caught within a try/catch block. If no other block is invoked the set_exception_handler function can set a function which will be called in the place of catch. Execution will stop after the exception_handler is called.
set_exception_handler Syntax:
set_exception_handler ( callable
$exception_handler
) : callable
<?php
function exception_handler($exception)
{
echo "Uncaught exception: ", $exception->getMessage(), "n";
}
set_exception_handler('exception_handler');
throw new Exception('Uncaught Exception');
echo "Not Executedn";
?>
#7 Non-Capturing Catches
Before PHP version 8, if you wanna catch an exception you will need to store it in a variable irrespective of its usage. You usually must specify the type whenever you use a catch exception. With this Non-Capturing Catch exception, you can ignore the variable.
Example:
try {
// Something goes wrong
}
catch (MyException $exception) {
Log::error("Something went wrong");
}
You can put it this way in PHP 8:
try {
// Something goes wrong
}
catch (MyException) {
Log::error("Something went wrong");
}
Summary:
Here we have explained the basic usage of exceptions and how to implement it in detail.You can quickly track the errors and fix the exceptions that have been thrown in your code. I hope this blog might be useful for you to learn what exception is and the correct usage of it.
If you would like to monitor your PHP code, you can try Atatus here.
13 Years Ago
can someone tell me what is wrong with the following:
function connect($db_host,$db_database,$db_user,$db_pass){
global $db_connection;
try {
$db_connection = mysql_connect($DB_HOST,$db_user,$db_pass, true);
if(!$db_connection) {
throw new Exception('MYQSL Connection Database Error: ' . mysql_error());
} else {
$connection = true;
}
catch (Exception $e) {
echo $e->GetMessage();
}
}
I receive:
Parse error: syntax error, unexpected ‘{‘
Refering to the { after try.
Thanks.
Edited
13 Years Ago
by Roebuc because:
spelling
Recommended Answers
You forgot a } before «catch». Try:
function connect($db_host,$db_database,$db_user,$db_pass) { global $db_connection; try { $db_connection = mysql_connect($DB_HOST,$db_user,$db_pass, true); if(!$db_connection) { throw new Exception('MYQSL Connection Database Error: ' . mysql_error()); } else { $connection = true; } } catch (Exception $e) { echo $e->GetMessage(); } }
Jump to Post
I ran your code through my interpreter and I didn’t get an error. Is it possible that you are running on PHP 4? I believe that try and catch are PHP 5 only.
Jump to Post
All 5 Replies
13 Years Ago
You forgot a } before «catch». Try:
function connect($db_host,$db_database,$db_user,$db_pass) {
global $db_connection;
try {
$db_connection = mysql_connect($DB_HOST,$db_user,$db_pass, true);
if(!$db_connection) {
throw new Exception('MYQSL Connection Database Error: ' . mysql_error());
}
else {
$connection = true;
}
}
catch (Exception $e) {
echo $e->GetMessage();
}
}
13 Years Ago
Thank you for the reply. That is definitely an oversight on my part I will test that when I get home, however, the syntax error was pointing to the line that contained:
try {
Obviously that is a mistake on my part that I need to fix, however, I think that would be a second syntax error. I will fix it when I get home and update. Thanks for the reply!
13 Years Ago
Unfortunately, that did not work. I made a few changes to the code but still receiving the same error:
function connect(){
global $db_connection;
try {
$this->db_connection = mysql_connect($DB_HOST,$this->db_user,$this->db_pass, true);
if(!$this->db_connection) {
throw new Exception('MYQSL Connection Database Error: ' . mysql_error());
} else {
$this->connection = true;
}
} catch (Exception $e) {
echo $e->GetMessage();
}
}
This error makes me think there is something in a function defined earlier. However, if I remove the try and catch statement, it works fine. Thanks for the help.
chrishea
182
Nearly a Posting Virtuoso
13 Years Ago
I ran your code through my interpreter and I didn’t get an error. Is it possible that you are running on PHP 4? I believe that try and catch are PHP 5 only.
13 Years Ago
Sorry for the long reply time. Just found that I am using PHP 4. Thanks for the info, I will see if I can get my hosting company to upgrade my php. Thanks.
Reply to this topic
Be a part of the DaniWeb community
We’re a friendly, industry-focused community of developers, IT pros, digital marketers,
and technology enthusiasts meeting, networking, learning, and sharing knowledge.