Зачем нужна @ в php

@

  • за

    Голосов: 6 19,4%
  • против

    Голосов: 25 80,6%

  • Всего проголосовало
    31

A1x

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

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
Это я намекаю на очередной антипаттерн "пустой обработчик исключения", который по факту ничем не лучше собаки
В похапэ нету finally, например. Поэтому если нам нужно чё-то подчистить, а потом перебросить исключение, то пустой обработчик --- таки необходимость.

И кстати, уважаемые, поучаствуйте в opensource разработке. Вот мне в HTTP_Request2 надо получить ошибку от stream_socket_client() и обернуть её в исключение. Делал я это раньше так:
PHP:
            $track = @ini_set('track_errors', 1);
            $this->socket = @stream_socket_client(
                $remote, $errno, $errstr,
                $this->request->getConfig('connect_timeout'),
                STREAM_CLIENT_CONNECT, $context
            );
            if (!$this->socket) {
                $e = new HTTP_Request2_ConnectionException(
                    "Unable to connect to {$remote}. Error: "
                     . (empty($errstr)? $php_errormsg: $errstr), 0, $errno
                );
            }
            @ini_set('track_errors', $track);
            if (isset($e)) {
                throw $e;
            }
Но тут появился товарищ, у которого вылезает Notice про неопределённую переменную $php_errormsg. Кроме того, я так понимаю, часть сообщений, которыми может гадить на экран stream_socket_client(), не попадают ни в $errstr, ни в $php_errormsg. Видимо мне вышеприведённый говнокод надо переписать как
PHP:
            $track   = @ini_set('track_errors', 1);
            $display = @ini_set('display_errors', 1);
            ob_start();
            $this->socket = stream_socket_client(
                $remote, $errno, $errstr,
                $this->request->getConfig('connect_timeout'),
                STREAM_CLIENT_CONNECT, $context
            );
            $buffer = ob_get_clean();
            if (!$this->socket) {
                $e = new HTTP_Request2_ConnectionException(
                    "Unable to connect to {$remote}. Error: "
                     . (empty($errstr)? (empty($php_errormsg) ? $buffer : $php_errormsg): $errstr), 0, $errno
                );
            }
            @ini_set('track_errors', $track);
            @ini_set('display_errors', $display);
            if (isset($e)) {
                throw $e;
            }
чё-нить забыл? и да, это иллюстрация, зачем в похапэ нужна собака.
 

A1x

Новичок
возможно скажу глупость, если ругается на неопределенную переменную я бы ее объявил где-нибудь сначала.
Хотя этой фичей track_errors никогда не пользовался, странно как-то откуда ни возьмись магическим образом появляется переменная $php_errormsg
так почему на нее тогда возбуждается нотайс если она появляется из track_errors? Или ее все-таки надо объявлять?
возможно если изначально кидать исключение на любой нотайс и выше это помогло бы избавиться от подобных костылей и собак заодно
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
error_get_last() пробовал?
Спасибо, попробую. Этот (относительно) новый костыль как-то упустил.

возможно скажу глупость, если ругается на неопределенную переменную я бы ее объявил где-нибудь сначала.
Хотя этой фичей track_errors никогда не пользовался, странно как-то откуда ни возьмись магическим образом появляется переменная $php_errormsg
Объявлять её надо было, конечно, о чём и баг-репорт пришёл. Магическим образом она появляется как раз из track_errors. Или не появляется, если ini_set() запрещён...

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

grigori

( ͡° ͜ʖ ͡°)
Команда форума
это иллюстрация, зачем в похапэ нужна собака.
не совсем. если запрет ini_set() через disabled_functions - поддерживаемая конфигурация и ожидаемая ситуация, лучше выставлять define (INI_SET_ENABLED) и потом по if (INI_SET_ENABLED)

оборачивать stream_socket_client() в ob_handler тебе не поможет - оно будет кидать ворнинг/ноутис, который будет ловиться каким-нибудь обработчиком, и до HTTP_Request2_ConnectionException дело не дойдет
ставить HTTP_Request2_ConnectionException обработчиком ошибок - плохая идея, т.к. в приложении скорее всего будет свой,
я бы скорее выставил error_reporting(0), и взял ошибку из error_get_last()['message'] (проверил, она там есть)

а вот если пользовательский обработчик ошибок не учитывает уровень error_reporting() и ловит все по своему усмотрению - то я бы оставил это на автора такого обработчика
 

A1x

Новичок
Sad Spirit
Ну вот я и пытаюсь кинуть исключение по факту невозможности установки соединения.
я имел в виду что-то вроде того как сделано в некоторых фреймворках, напр в кохане
PHP:
function error_handler($code, $error, $file = NULL, $line = NULL)
	{
		if (error_reporting() & $code)
		{
			// This error is not suppressed by current error reporting settings
			// Convert the error into an ErrorException
			throw new ErrorException($error, $code, 0, $file, $line);
		}

		// Do not execute the PHP error handler
		return TRUE;
}

set_error_handler('error_handler');
тогда было бы
PHP:
try {
     $this->socket = stream_socket_client(...);
} catch (ErrorException $e) {
    throw new HTTP_Request2_ConnectionException($e->getMessage());
}
разве этого было бы не достаточно?
 

weregod

unserializer
только как-то так
PHP:
set_error_handler(array('Core_Error_Handler', 'socket');
try {
     $this->socket = stream_socket_client(...);
} catch (Core_SocketException $e) {
    throw new HTTP_Request2_ConnectionException($e->getMessage());
}
restore_err...
 
  • Like
Реакции: A1x

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
не совсем. если запрет ini_set() через disabled_functions - поддерживаемая конфигурация и ожидаемая ситуация, лучше выставлять define (INI_SET_ENABLED) и потом по if (INI_SET_ENABLED)
Лучше бы от ini_set() вообще избавиться, всё равно придётся писать код, который будет заточен на работу когда
Код:
track_errors = Off
disable_functions = ..., ini_set, ...
оборачивать stream_socket_client() в ob_handler тебе не поможет - оно будет кидать ворнинг/ноутис, который будет ловиться каким-нибудь обработчиком, и до HTTP_Request2_ConnectionException дело не дойдет
ставить HTTP_Request2_ConnectionException обработчиком ошибок - плохая идея, т.к. в приложении скорее всего будет свой,
я бы скорее выставил error_reporting(0), и взял ошибку из error_get_last()['message'] (проверил, она там есть)

а вот если пользовательский обработчик ошибок не учитывает уровень error_reporting() и ловит все по своему усмотрению - то я бы оставил это на автора такого обработчика
Пользовательский обработчик тут --- это из области казуистики. Предполагается, что PEAR'овский пакет не должен выводить при работе сообщений об ошибках (включая E_NOTICE, а для свежих пакетов и E_STRICT), а ошибки оборачивать в исключения. Пользователь, соответственно, должен исключения ловить, а не пытаться повторить эту работу. Если кто-то помешает исключение бросать --- ССЗБ.

Я попробовал варианты, в принципе error_get_last() (спасибо fixxxer) работает. Вариант с set_error_handler() работает тоже.

Теперь о весёлом: stream_socket_client() может на одно подключение испражниться несколькими warning'ами. У меня тут локально что-то SSL не живёт, поэтому происходит, например, следующее:
Код:
Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:func(144):reason(134) in ...\HTTP_Request2\HTTP\Request2\Adapter\Socket.php on line 322

Warning: stream_socket_client(): Failed to enable crypto in ...\HTTP_Request2\HTTP\Request2\Adapter\Socket.php on line 322

Warning: stream_socket_client(): unable to connect to ssl://google.com:443 (Unknown error) in ...\HTTP_Request2\HTTP\Request2\Adapter\Socket.php on line 322
В результате вариант с error_get_last() даёт нам в сообщении исключения следующее:
Код:
Unable to connect to ssl://google.com:443. Error: stream_socket_client(): unable to connect to ssl://google.com:443 (Unknown error)
а вариант с предложенным A1x обработчиком:
Код:
Unable to connect to ssl://google.com:443. Error: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:func(144):reason(134)
Т.е., видимо, надо писать обработчик, который будет собирать тексты warning'ов, но не бросать исключение. А потом все эти тексты вставлять в сообщение исключения. Грубое циничное нецензурное слово.
 

A1x

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

grigori

( ͡° ͜ʖ ͡°)
Команда форума
несколько ворнингов за один вызов - это жестко ))) сочуствую

A1x, потому что суть проблемы видна только во 2й ошибке из 3х
 

A1x

Новичок
ну тогда можно такой обработчик с exception chaining'ом
PHP:
    protected $_socketException = NULL;

    protected function _handleSocketError($code, $error, $file = NULL, $line = NULL) {
        if (error_reporting() & $code) {
            $this->_socketException = new ErrorException($error, $code, 0, $file, $line, $this->_socketException);
        }
        return TRUE;
    }
PHP:
set_error_handler(array($this, '_handleSocketError'));
$this->_socketException = NULL;
$this->socket = stream_socket_client(...);
restore_error_handler();
if ($this->_socketException instanceof ErrorException) {
    throw $this->_socketException;
}
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
A1x 1й и 2й ворнинги просто потеряются, останется только эксепшн на последний
 

A1x

Новичок
grigori там предыдущий эксепшн передается последним параметром в конструктор - $previous
потом его можно получить из Exception::getPrevious
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
а, ну да, только надо переопределить класс и добавить getErrorMessageStack()
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
grigori там предыдущий эксепшн передается последним параметром в конструктор - $previous
потом его можно получить из Exception::getPrevious
Сделал в результате без заморочек с getPrevious(), все Warning'и сразу идут в сообщение.

Ну и возвращаясь к теме треда: собак в этом месте кода больше нету.
 

weregod

unserializer
Вспомнился еще аргумент в пользу обессобачивания. Волею судеб был написан такой код
PHP:
@eval($code);
и когда случался FATAL в этом eval(), падал весь скрипт, ловить багу было тяжко, ибо исполнялись кастомные шаблоны, в дефолтной поставке системы никаких FATAL-ов не было.
 

ksnk

прохожий
Ну и прo меня тогда :).
Несложный и короткоживущий socket-server для поддержки чата support'а. Служба не очень востребована, так что закрывается через 10 минут молчания, ну и написана на php. При каждой попытке обратится в саппорт, клиентский компьютер проверяет наличие сервера, если он есть, - пользуемся им, если нет - стартуем заново. Функция старта сервера такая:
PHP:
function start_server(){
   $handle=socket_create(...);
   $result=@socket_connect(...);
   if($result !== false) {
       socket_close(...)
       self::log('server already exists!');
       return true;
   }
   ...
   // start server
}
Собственно вопрос такой - как исправить собаку в этом месте? Собака нужна, чтобы не плодился ненужный мне варнинг про невозможность установки соединения к несуществующему серверу - штатная ситуация.

Может решение уже было и я его в этих 5 страницах не увидел?
 

scorpion-ds

Новичок
Уже постил этот код тут:
PHP:
foreach ($lst as $item)	{
						
			$dom = new DOMDocument();
			$dom->load($item);
			
			if(@$dom->validate())	{
				//***
			}
			
		}
Зачем нужна функция "$dom->validate()" которая проверяет на валидность к примеру XML, но при этом еще и вызывает исключение? Это как если бы код if(is_file('test.txt')) вызывал бы исключение.
Так что голосовал за @, пока не будет отлажен нормально механизм исключений в PHP.
 
Сверху