Я предполагаю, что вы заинтересованы именно в такой функции, как getimagesize
, которая не возвращает никаких кодов ошибок и усложняет нам задачу. Но не невозможно.
Документация для getimagesize
гласит:
Если доступ к изображению с именем файла невозможен или если это недопустимое изображение, getimagesize()
выдаст ошибку уровня E_WARNING
. При ошибке чтения getimagesize()
сгенерирует ошибку уровня E_NOTICE
.
Следовательно, вам нужно сделать две вещи:
- Получать уведомления об ошибке и действовать по ней как-то
- Не отображать ошибку или как-либо иначе влиять на выполнение вашей программы (в конце концов, вы сами позаботитесь о любых ошибках с помощью кода обработки ошибок)
Вы можете достичь первого, используя set_error_handler()
и restore_error_handler()
. Вы можете достичь второго с оператором контроля ошибок @
.
Итак, код должен выглядеть примерно так:
// Set our own error handler; we will restore the default one afterwards.
// Our new error handler need only handle E_WARNING and E_NOTICE, as per
// the documentation of getimagesize().
set_error_handler("my_error_handler", E_WARNING | E_NOTICE);
// No error has occured yet; it is the responsibility of my_error_handler
// to set $error_occurred to true if an error occurs.
$error_occurred = false;
// Call getimagesize; use operator @ to have errors not be generated
// However, your error handler WILL STILL BE CALLED, as the documentation
// for set_error_handler() states.
$size = @getimagesize(...);
// At this point, my_error_handler will have run if an error occurred, and
// $error_occurred will be true. Before doing anything with it, restore the
// previous error handler
restore_error_handler();
if($error_occurred) {
// whatever
}
else {
// no error; $size holds information we can use
}
function my_error_handler($errno, $errstr, $file, $line) {
global $error_occurred;
// If the code is written as above, then we KNOW that an error
// here was caused by getimagesize(). We also know what error it was:
switch($errno) {
case E_WARNING: // Access to image impossible, or not a valid picture
case E_NOTICE: // Read error
}
// We could also check what $file is and maybe do something based on that,
// if this error handler is used from multiple places. However, I would not
// recommend that. If you need more functionality, just package all of this
// into a class and use the objects of that class to store more state.
$error_occurred = true;
return true; // Do not let PHP's default error handler handle this after us
}
Конечно, это не очень легко обслуживать (у вас есть глобальная переменная $error_occurred
, и это не очень хорошая практика). Таким образом, для решения, которое не только работает, но и хорошо спроектировано, вы бы упаковали все это в классе. Этот класс будет определять:
- Метод, который реализует обработчик ошибок (
my_error_handler
в приведенном выше примере). Чтобы установить объектный метод в качестве обработчика ошибок вместо глобальной функции, вам нужно вызвать set_error_handler
с подходящим первым параметром; см. документацию для callback
.
- Метод, который позволяет классу установить обработчик ошибок, выполнить некоторый код по вашему выбору, сохранить флаг «ошибка произошла при выполнении вашего кода» и восстановить обработчик ошибок. Этот метод может, например, возьмите
callback
, предоставленный вашим кодом вызова, и массив параметров и используйте call_user_func_array
для его выполнения. Если во время выполнения вызывается обработчик ошибок, установленный из # 1 выше, отметьте это в переменной вашего объекта. Ваш метод вернет возвращаемое значение call_user_func_array
вызывающему коду.
- Метод или переменная, которую вызывающий код может использовать для доступа к результату из # 2 выше.
Итак, если этот класс называется ErrorWatcher, ваш код вызова будет выглядеть примерно так:
$watcher = new ErrorWatcher;
$size = $watcher->watch("getimagesize",
array( /* params for getimagesize here */ ));
// $size holds your result, if an error did not occur;
// check for errors and we 're done!
switch($watcher->report_last_error()) {
// error handling logic here
}
... что приятно и аккуратно и не мешает с глобальными переменными. Надеюсь, я объяснил это достаточно хорошо, чтобы вы могли самостоятельно написать класс ErrorWatcher. : -)