Правильная структура вызова классов

whirlwind

TDD infected, paranoid
>функции a() делать? проверять ===null потом ==0 потом уже -1 или 1, что конечно же на 2 порядка удобнее

Если не нужно - не проверяй. Но если это метод валидации, то какой в нем смысл, если результат не нужен? Всё это вопросы дизайна. Не нужны исключения в 99%. В результате все равно все важные исключения будут отловлены на том уровне, откуда был вызван код, выбрасывающий исключения, а в не важных исключениях нет смысла.

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

whirlwind

TDD infected, paranoid
>Но это же противоречит фразе
Не противоречит, потому что скопление функций где

> количество строк на функцию/метод превышает 3/4 от видимого окна

не есть надежный код.
 

whirlwind

TDD infected, paranoid
Боюсь что Вы со своими шутками-прибаутками обратились не по адресу.
 

itprog

Cruftsman
я уже говорил, хватит тут показывать на примере бесполезных echo $e->getMessage и отлов в пределах одного уровня. Это не аргумент в данном случае. Приведите примеры где у вас между выбросом и отловом исключения несколько вызовов, т.е. бектрейс боле одного элемента.
Если речь идет о коде выше, то это лишь ответ на вопрос:
Зачем? И чем это отличается от


if ( !$this->myCall() ){

}
 

zerkms

TDD infected
Команда форума
хехе... ;)

а вспомним с чего всё началось:

что "не рекомендуется" юзать исключения в конструкторах

затем был приведён абстрактный код абстрактного метода который мужественно был разрулен с помощью ретурн и совсем без эксепшнов...
хм...а как использовать этот самый return в конструкторе??? (добавлять ещё один метод??)
 

nut

Новичок
Автор оригинала: Guest_w

require_once(PATH_TO_CLASS.'Mysql.class.php');

$c_m = new DB_mysql();
$ch = new Test($c_m);
$c_m->connect();

$ch->getGroup();

class Test
{
var $db; // private
var $error_mes='';
var $error=0;


function Test(&$db){

if(is_object($db)){
$this->db=&$db;
}
else {

Ну и т.д.
Я использую подобную систему. Это вроде самое нормальное.
 

whirlwind

TDD infected, paranoid
>хм...а как использовать этот самый return в конструкторе??? (добавлять ещё один метод??)

Так и будем по кругу ходить? Может стоит топик сначала перечитать и попытаться осмыслить разжеванное на трех страницах? :) Размещая некий важный код в конструкторе, вы обрекаете тем самым ваш объект на единственно доступный вариант инициализации. Если появится необходимость перенастроить объект, то кроме как создать его заново (т.е. вызвать конструктор посредством new) вариантов нет. Исключения это окольный выход из ситуации в данном случае. НО! Это подталкивает вас перекладывать обработку ошибок на исключения вообще по всему коду. Например, вместо того, что бы придать классу большей гибкости и добавить метод коннекта, вы реализуете коннект в конструкторе и пихаете исключения. Теперь представьте, что вы наследуете и инкапсулируете хотя бы 3 таких же кривых класса в одной иерархии. Сколько различных параметров придется предавать в конструктор самого верхнего наследника? Учитите, что в случае наследования, вы не сможете передать объект, т.к. настроенный объект вы можете получить только после конструкции, а итоговый конструктор получается всего один! По этому я и говорю, любой конструктор должен иметь возможность быть исполнен без аргументов. А что бы не было безвыходных ситуаций, когда аргументы все же необходимы, для этого в конструкторе не должно быть никакого важного кода. Если у вас максимальный уровень наследования один-два класса глубиной, если ваши классы не сложнее актив роу на уровне: сопоставить атрибуты и сформировать запрос, если вы любитель каждый раз изобретать велосипед и не цените свой собственный труд, то пишите с исключениями и даже с исключениями в конструкторе. Когда поприбавится опыта и вы захотите отрефакторить свои классы или же предпримите попытку многократно использовать собственный код, то все эта кривизна выплывет обязательно.
 

Andreika

"PHP for nubies" reader
whirlwind
не будем на 4 страницу лезть... просто не надо писать безаппеляционно "нельзя так делать!" и точка. а то потом же оказывается, что "делать можно, но не рекомендуется", потом "иногда конечно так даже лучше, но..." и в итоге откзывается, что "вот если сделать так и здесь прикрутить, то вот и окажется что так делать нельзя, как я и говорил!"
тем более, что классы они разные бывают
 

Guest_w

Новичок
Блин я перечитал все что здесь было написано у меня волосы зашевелились во всех даже самых непреличных местах :)

одним словом далеко мне еще до полного осознания таких дискуссий :(

можно вопрос, будет ли это хорошим тоном, если в одном из классов я создам объект другого класса через NEW ?
например,
class class1
{

var a;

function t1()
{
$this->a = &new class2;
}

}
 

whirlwind

TDD infected, paranoid
вполне... если этот класс не выкидывает исключения. если выкидывает, то хороший тон меняется на хороший бас
PHP:
function t1()
{
   try {
     $this->a = &new class2;
   }catch(){
      .....
   }
}
 

itprog

Cruftsman
Только это не по правилам ООП, т.к. при таком раскладе класс class1 зависит от класса class2. Это хорошо видно при TDD, когда требуется изолировать класс, а все "вспомогательные" классы заменить моками

-~{}~ 16.02.06 01:31:

whirlwind
За что так не любим исключения? :)
 

[sid]

Новичок
Этот топик наглядно показал неумение спорящих выдерживать тему дискуссии. Обидно господа.

Что касается исключений. Может стоит сделать шаг назад и задать себе вопрос: "А можно ли вообще сравнивать традиционные методы обработки ошибок (характерные для функционального подхода) и исключительные ситуации (характерные для ООП)?". Думаю сравнивать можно, но не стоит забывать, что качество кода напрямую не зависит от используемого стиля разработки. Поэтому некорректно говорить, что "исключения нужны тем, кто не может/не хочет писать надежный код". Неужели автор не видел качественных ООП систем использующих механизм исключений?! Качественный и надежный код можно написать с использованием любого подхода. Вопрос совсем в другом. Вопрос в себестоимости такого кода и стоимости его сопровождения.

Сравнивая традиционный подход и исключения можно выделить несколько аспектов различающий эти подходы

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

В случае exceptions место генерирования и обработки может быть удалено друг от друга на более дальнее расстоние. whirlwind очень критично заметил что это не имеет смысла. Действительно чем дальше расположены эти две точки кода, тем менее эффективно мы можем обработать ошибку. Но нас ведь никто ни к чему не принуждает. Мы можем расположить обработку там, где ошибку можно обработать оптимально, а как показывает моя практика это "оптимально" является точкой кода на удалении 2х-3х уровней стека от точки генерирования ошибки.

А разделение места генерирования и обработки ошибки (более чем 1 уровнем стека) это основное преимущество, которе дают нам exceptions. Ведь в системном коде мы знаем что за ошибка произошла, но мы не знаем, как корректно ее обработать в данной ситуации. Подчеркну, что в приложении могут быть правила обработки ошибок, которые зависят не только от типа ошибки, но и от других факторов. Скажем три раза пытаемся подключиться к серверу DB если нет, то переходим к следующему в списке (не такое уж надуманное правило, особенно для клиентских приложений).

2. Информативность сообщения об ошибке
Как вам это:
PHP:
return -1;
Ну и что за ошибка тут произошла? Ну конечно, надо отдать должное, нормальный программист сделает так:
PHP:
return ERR_DB_CONNECT_FAILED;
Уже значительно лучше, но неужели вы будете спорить, что следующий код значительно информативней:
PHP:
throw new DbConnectFailedException($host, $reason);
Так как механизм исключений основан на объектной модели, то конкретный тип исключительной ситуации может быть заточен под конкретную ошибку и нести столько информации, сколько необходимо для корректного восстановления потока выполнения приложения.

3. Объединение ошибк в группы
Тот внешний catch приложения (или просто exception handler), который так сильно критиковался whirlwind'ом, на самом деле играет очень важную роль. Он позволяет централизованно обрабатывать ошибки. Скажем все ошибки работы с БД мы должны записать в один лог, а ошибки валидации данных в другой лог, а на информацию о других ошибках отправить администратру по почте. В данном случае транспортировка кодов ошибок, вроде:
PHP:
ERR_DB_CONNECT_FAILED;
ERR_DB_CONNECT_REFUSED;
ERR_DB_ACCESS_DENIED;
до места обработки вызовет значительные затруднения. Более того, как мне определить в обработчике, что ERR_DB_CONNECT_REFUSED и ERR_DB_ACCESS_DENIED являются подтипами ERR_CONNECT_FAILED? Ведь обе ошибки (ERR_DB_CONNECT_REFUSED и ERR_DB_ACCESS_DENIED) относятся к ошибкам "отказа в соединении" (ERR_CONNECT_FAILED), и логика их обработки может быть одинаковая, а может быть и разная. Все зависит от требований к приложению. Безусловно это проблема решаемая с помощью своего собственного обработчика, который может организовывать коды ошибок в дерево для выявления групп и подгрупп.
Но согласитесь, нижеприведенный код приятнее и понятнее
PHP:
class dbConnectionException extends exception{}
class accessDeniedDbException extends dbConnectionException{}
class connectRefusedDbException extends dbConnectionException{}
я уже не говорю об обработке
PHP:
... } catch ( dbException $e ) {
    // Пишем в db.log
} catch ( validationException $e ) {
    // Пишем в validation.log
} catch ( fooException $e ) {
    // Отправляем писмо администратору
} catch ( Exception $e ) {
   // Общие правила обработки
}
Этим постом я хотел показать, что нет нерешаемых задач в обоих методиках. И там и там код может быть качественным и надежным. Вопрос, как я уже сказал, в стоимости. Поэтому "если вы не любитель каждый раз изобретать велосипед и цените свой собственный труд", то думаю вы постараетесь оценить преимущества, которые предоставляет вам ООП и механизм исключений.
 

whirlwind

TDD infected, paranoid
> Неужели автор не видел качественных ООП систем использующих механизм исключений?!

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


>Ну и что за ошибка тут произошла? Ну конечно, надо отдать должное, нормальный программист сделает так:

return ERR_DB_CONNECT_FAILED;

Уважаемый, извините конечно, но вы насмешили мой тапки. Эдак на проект констант не напасешься. Если я вызвал метод connect, то максимум что я могу предположить насчет результатов это true - есть коннект, false - нет коннекта. Третьего тут извините не дано. Вообще лично я стремлюсь (и всем советую) к двум исходам вызова: true и false (естессно это не относится к геттерам). Т.к. манипуляции выполняются как правило надо объектами, расшифровка инкапсулируется внутри объекта. Но при правильном дизайне кода не требуется никаких расшифровок, потому что функции решают вполне определенные задачи c ограниченным количеством прозрачно-ясных вариантов отработки.
 

itprog

Cruftsman
Уважаемый, извините конечно, но вы насмешили мой тапки. Эдак на проект констант не напасешься. Если я вызвал метод connect, то максимум что я могу предположить насчет результатов это true - есть коннект, false - нет коннекта.
И каким образом определить причину "нет коннекта"? А что если требуется разная реакция на разные причины?
Видел. Но я не видел решений, в которых использование исключений было бы оправдано.
Покажите примеры, где вы видели использование исключений не оправданным (интересуют ООП приложения). Какие моменты требуют заглянуть в мануал (и зачем кстати?)

К примеру, agavi.org (бывшая mojavi 3), используются исключения. Почему не оправдано использование?
 

whirlwind

TDD infected, paranoid
>И каким образом определить причину "нет коннекта"? А что если требуется разная реакция на разные причины?

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

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

Creole например. Он выбрасывает исключения одного типа как найтив SQL errors, так и на ошибки работы собственных алгоритмов. И если мне потребуется узнать, почему же вдруг я не смог приконнектиться, мне кроме как отпарсить масягу делать нечего. А я хотел бы иметь воздожность получить некий код, который мне скажет - у тебя логин/пароль/база неверная. Как это может выглядеть? Да хотябы так
PHP:
define("ERR_INV_LOGIN",0x01);
define("ERR_INV_NAME",0x02);
define("ERR_INV_PASS",0x04);
define("ERR_SOME_ERR",0x08);
etc...

// не хотим обработать ошибку
if ( $obj->someCall() ) return false;

// хотим детально обработать ошибку
if ( !$obj->someCall($this->call_param) ){
    $es = $obj->getErrorState();
    if ( $es & ERR_INV_LOGIN || $es & ERR_INV_PASS) ) ...
    // хотим обрабатываем другие, не хотим - не обрабатываем
    if ( $es & ERR_INV_NAME ) $this->some_param = "blablabla"
и т.п. ну булеву алгебру все знают, по моему так удобнее и быстрее чем парсить текст


>Какие моменты требуют заглянуть в мануал (и зачем кстати?)

Моменты, связанные с тем, что вместо элементарного true/false мне нужно знать класс исключения, а так же не забывать, что при использовании этой библиотеки опираться на прототип метода мало. Я обязан каждый вызов обернуть сеткой, что бы избежать неожиданных исключений ведь ни в одном мануале не описывается в каких именно случаях и с какими именно вызовами связано то или иное исключение. Естессно, подразумевается, что разработчик будет читать сообщения инкапсулируемые исключениями. Ну а деваться то и некуда... Вот разработка и протекает из за этого по принципу "метод научного тыка": попробовал - отловил - сделал выводы, вместо того, что бы сразу написать правильно.
 

[sid]

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

Я обязан каждый вызов обернуть сеткой, что бы избежать неожиданных исключений
Нет не обязаны. В этом случае приложение аварийно завершится. И это правильно. Нет смысла продолжать выполнения приложения... вызывать query, fetchи если у вас connect обломался (а ведь именно так работает скажем mysql_connect()). В случае с exceptions программа вылетит, потому как далее работать она просто не сможет, а если вы можете как то это исправить, то и все карты вам в руки.

И говоря уже о крректном ООП, не очень красиво когда объект берет на себя функции парсина ошибок о сообщениях и прочего. Так как все мы знаем о принципе SingleResponsibility.

И самое насущное, и чему почему то не придают внимание - это дистанция м/у точками генерации ошибки и ее отлова. Если у меня есть такой пользовательский код:
Код:
$ar = new UserActiveRecord();
$ar->setName($name);
$ar->setFoo($foo);
И скажем AR делегирует объекту валидатору для проверки name и foo. И скажем при валидации name происходит ошибка, то AR должен об этой ошибке как то уведомить пользовательский код, то есть транспортировать ошибку на уровень вверх. Ну ладно, траспортирует он этот чертов false клиентскому коду. А как он (клиентский код) узнает информацию об ошибке? Для этого ему надо будет иметь доступ к валидатору (я знаю знаю... IoC, DI и красота дизайна). Таких случаев кстати не мало. И в таких случаях exception крайне полезен
 

whirlwind

TDD infected, paranoid
>И в таких случаях exception крайне полезен

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