За последние 24 часа нас посетили 22556 программистов и 1049 роботов. Сейчас ищут 658 программистов ...

Задачка с классами (ООП vs процедуры)

Тема в разделе "Прочие вопросы по PHP", создана пользователем Adamant, 25 июл 2007.

Статус темы:
Закрыта.
  1. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    я не говорил легко и просто. Планирование остается скрупулезным, но ООП дает для этого подход, в том числе разделяя планирование и кодирование. А вот писать код становиться легче и быстрее.
     
  2. Davil

    Davil Guest

    stas_t сочувствую. Видимо тебе действительно не пришлось увидеть действительно хорошо реализованный проект с ОО подходом. Особенно по истории с java =). Объекты должны были реализовывать методы для доступа к внутренней инфы (при хорошем тоне).
    эра register_globals показала, что это не лучший способ проектирования.
    Алгоритмически оперируя объектами и их методами =)
    Как раз ОО подход реализует неплохой способ планирования. Согласись - проще оперировать объектами, чем непонятными субстанциями.
     
  3. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    потому, что количество баз данных может быть больше одной.
     
  4. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    вот это действительно жуть.
     
  5. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    действительно, прошу прощения, в оригинале было "легко и быстро". прошу в моём посте все вхождения строки "легко и просто" читать как "легко и быстро". смысл не меняется. а планирование и кодирование вообще всегда разделены и никогда вместе не ходят. если вы имели в виду проектирование, то да, действительно, диаграмма классов может автоматически сгенерировать объект. но проект строится не на диаграмме классов, а на примерах использования (use case), которые и согласовываются с заказчиком. после этого вы можете заняться разрисовкой объектов, можете рисовать экраны, писать структуру базы или сразу броситься программировать. как хотите. но проект должен будет отвечать согласованному тз, есть у вас диаграмма классов или нет.

    Davil
    давайте так. мухи -- отдельно, котлеты -- отдельно. register_globals никакого отношения к обсуждаемой теме не имеет. или вы сейчас собираетесь при людях заявить, что все глобальные переменные -- это зло, потому что программист имеет к ним доступ на запись из любой точки программы?

    алгоритмически описывая происходящие процессы

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

    я бы сказал, что это удобно. на вкус и цвет...

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

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

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

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

    короче, главное -- всё правильно организовать, использовать или не использовать при разработке ооп -- решайте сами. [flame stopped]

    Горбунов Олег
    огромное спасибо за ссылку. по бучу изучали в институте теорию разработки систем. много тёплых воспоминаний.
     
  6. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    Горбунов Олег, вот бы нашёлся добрый человек и отфильтровал бы оттуда всю воду.. ;)

    хранить их в виде массива и во все функции передавать в качестве параметра номер? а если нужно воспользоваться базой sqlite, а в вызываемой функции юзается mysql_query? копипастить функцию и изменять её? а если она вызывает ещё десяток - их тоже копипастить?

    хотя, да, без объектов можно извертнуться: передавать массив коллбэков для работы с нужной субд... тока это ни что иное, как кривой велоспед реализующий то для чего предназначен ООП...
     
  7. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Блин, отлучился на 5 часиков, а нафлудили шо пистец.. хотя есть чё почитать... Лано, к делу.

    Как уже тут упоминалось, соединений может быть несколько, это раз. Соединяться можно вообще с разными по типу базами (приходилось иметь дело одновременно с MySQL и MSSQL как-то давно).

    Да, конечно можно использовать глобальные массивы для ошибок и прочие служебные переменные. Только вот я не вижу смысла засорять глобальное пространство имён ими - есть возможность нечаяно где-то что-то туда записать а потом долго искать ошибку. Глобально нужно держать только то, что используеться больше чем в одном классе/фаиле.

    Чего я добился? Того, что мне эта переменная не мешаеться, не нужно помнить что она такая есть и что её нельзя трогать. Да и если объявляешь к примеру коннект к базе глобальной переменной (у меня щас так в бумтайме - переделывать когда я пришел было уже поздно) а потом везде global $database, а потом ещё в mysql_query не забыть подставить. Класс меня от таких тонкостей избавляет, потому что есть метод query который и линк к базе берёт из поля класса и подставляет его автоматом в mysql_query. Да можно сделать такую-же функцию. Только вот скорее всего это будет что-то типа db_query, потому что в большом проэкте много всего и вполне вероятно что появиться ещё какая нить *_query функция.

    Ещё пример - понадобилось что-то действительно извращённое. Что мы сделаем с функциями? Напишем ещё одну или подправим её. С объектом проще - наследуем его и переопределяем нужный(е) методы - легко и просто. И мне лично приходилось так делать иногда.

    2All
    Автору топика особенно: http://php.ru/forum/viewtopic.php?p=45997#45997 - мною выложенный движок. Ничего плохого никто про него не сказал, так, критика по мелочам, которые специфичны для проэкта и носят скорее характер "к чему бы придраться". Довольно неплохая модель и реализация движка, прекрасно себя зарекомендовавшая в полевых условиях. Так что можем продолжить ддискуссию на примере этого движка, а новичкам там есть на что посмотреть.
     
  8. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    dark-demon
    с трудом улавливаю вашу мысль. зачем во всех функциях нужны параметры подключения?

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

    в ооп-варианте вы бы поступили точно также. создали бы по объекту на подключение и из функции передавали бы запросы в один из этих (глобальных) объектов.

    шило на мыло, короче.

    а по поводу кривого велосипеда... неизвестно ещё, какой вариант кривее.

    p.s. кстати, массив параметров подключений к базам гораздо удобнее хранить в одном массиве и подключать из файла, скажем, db_params.php, чем определять в разных классах.

    Psih
    интересная постановка. засорять глобальное пространство объектами, размер и реализация которых от вас скрыты вас не напрягает, а засорять его детерминированным массивом с 7-ю параметрами на базу + функция-обёртка -- это кощунство, так что ли? и как вы себе представляете случайную запись в глобальный массив $DB_PARAMS ?

    о том и речь

    зато вам надо помнить о существовании объекта с подключением к базе. а использования во всех функциях global $database (если вас оно, конечно, напрягает) можно избегать использованием функции-обёртки.

    это именно и будет db_query (), и в большом проекте совсем не обязательно должна появиться другая база. немного я могу назвать причин, требующих переключить большой проект на новую базу.
     
  9. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    stas_t, дело не в том, что причин не много, а в том, что они бывают. и ооп тут позволяет сократить объём геморроя...
    давайте приводить код..

    что предлагаю я:
    Код (Text):
    1. function getusers ($registry, $city) {
    2.   $db= $registry['db'];
    3.   $users= $db->get2d('select * from users where location="'.city.'"');
    4.   return $users;
    5. }
    6.  
    7. $peterusers1= getusers($registry, 'petersburg');
    8. $newregistry= $registry;
    9. $newregistry['db']= new SQLDB('mysql://login:password@notlocalhost/datbasename/');
    10. $peterusers2= getusers($newregistry, 'petersburg');
    11.  
    12. $peterusers= array_merge($peterusers1,$peterusers2);
    как видим, функция не шарится в глобальной области видимости и имеет одну единственную точку входа - точку её вызова (возвращаемое значение целиком и полностью зависит от переданных ей параметров и больше ни от чего). это позволяет, например, с лёгкостью подменить бд с которой она будет работать при этом не создавая её модифицированной копии. более того, другие вызываемые ею функции также будут работать с другой базой данных.
    назовём это "динамической инъекцией" ;-)
     
  10. Davil

    Davil Guest

    У монеты 2 стороны. Знаете как бывает. Это может стать халтурой, которая в последствии попортит много нервов.
    Четкая же структура помогает проектировать и расширять.
    Не уловили иронии =)
    Я рад что могу общаться с таким опытным человеком. Но всеже считаю структурный подход пережитками прошлого.
    К примеру, есть у меня один проект, который я поддерживаю. Он написан на php3 еще в 99 году.
    Причем написан очень опытными людьми но, естественно, структурным подходом.
    По этому проекту я для себя выяснил, что будующее за ООП в любом случае. Безапеляционно.
     
  11. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    dark-demon
    насколько мне известно, функции всегда шарятся в глобальной области видимости. а приведённый вами кусок кода также легко написать и на функциях. и тому кто будет его поддерживать не придётся ломать себе голову по поводу странного класса SQLDB и непонятного метода get2d.

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

    знаете, когда я сегодня смотрю на то, что сам писал в 1998 году, становится смешно до слёз. все мы растём и чему-то учимся каждый день. мой опыт, "сын ошибок трудных", подсказывает мне, что использование ооп не несёт обещанных простоты и скорости, скорее наоборот -- усложняет и замедляет разработку и поддержку систем.
     
  12. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    stas_t
    Ну про замедляет - согласен. Прежде чем сделать, надо подумать :D

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

    Anonymous Guest

    Во-во, мое мнение высказал, ага.
     
  14. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
     
  15. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    ну, если начинать в лоб с вашего варианта (в котором, похоже, пропущены строки с инициализацией и подключением), то можно сделать так:
    Код (Text):
    1. db_load_params ();       // create $DB_PARAMS with 'db1' and 'db2' entries; not in original post
    2. db_connect_read ('db1'); // connect to db1; not in original post
    Код (Text):
    1. db_connect_read ('db2'); // connect to db2
    2.  
    3. function get_users_array ($db_id, $city)
    4. {
    5.   return db_fetch_array ($db_id, "select * from users where location='$city'");
    6. }
    7.  
    8. $peterusers1 = get_users_array ('db1', 'petersburg');
    9. $peterusers2 = get_users_array ('db2', 'petersburg');
    10. $peterusers = array_merge ($peterusers1, $peterusers2);
    причём в большинстве систем, работающих с одной базой, передавать параметр $db_id не придётся.

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

    p.s. внимательный читатель обратит внимание, что я позволил себе изменить названия функций дабы упростить понимание сюжета. наличие db_connect_read подразумевает наличие db_connect_write. это в случае распределённой базы, когда подключение для чтения осуществляется к одному серверу, а для записи -- к другому. параметры 'host_read' и 'host_write' определены, понятно, в $DB_PARAMS, наравне с 'user', 'password', 'database' и 'server_type'
     
  16. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    а можно привести содержание db_fetch_array, способной работать с различными субд?
    нафига такой финт ушами?
     
  17. Davil

    Davil Guest

    антирепликация =)
     
  18. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    можно, конечно, но не вижу смысла. мы можем меряться библиотеками сколь угодно долго, здесь не будет победителя. хотя... разве только для чисто академических целей, но ни в коем случае не в рамках соревнования:
    PHP:
    1. <?php
    2. function db_fetch_array ($sql)
    3. {
    4.     if ($cursor = mysql_unbuffered_query ($sql))
    5.     {
    6.         $lst = array ();
    7.  
    8.         while ($a = mysql_fetch_assoc ($cursor))
    9.             $lst[] = $a;
    10.         mysql_free_result ($cursor);
    11.  
    12.         return $lst;
    13.     }
    14.  
    15.     db_error_log ($sql);
    16.     return false;
    17. }
    18. ?>
    перед вами пример классической обёрточной функции, возвращающей в массиве строки запроса из текущего подключения к базе (в нашем случае мускул). данный код обладает неоспоримыми преимуществами в эффективности и простоте. используются функции mysql_unbuffered_query и mysql_fetch_assoc. если необходимо будет одновременно в одном скрипте подключаться к разным базам одной субд мы, понятно, добавим параметр с подключением. если же встанет задача (как в данном случае) подключаться к другой субд, то необходимо обеспечить развлетвление, позволяющее использовать правильные функции для выполнения запроса и получения результата.

    внимательный читатель, несомненно, помнит о том, что параметры используемых подключений у нас хранятся в глобальной переменной $DB_PARAMS. напомним её структуру (для простоты используется один сервер для чтения и записи):
    PHP:
    1. <?php
    2. $GLOBALS['DB_PARAMS'] = array ('db1'=>array ('host_read'=>'localhost'
    3.         , 'host_write'=>'localhost'
    4.         , 'username'=>''
    5.         , 'password'=>''
    6.         , 'database'=>'first'
    7.         , 'server_type'=>'mysql'
    8.         , 'connection'=>null
    9.         )
    10.     , 'db2'=>array ('host_read'=>'localhost'
    11.         , 'host_write'=>'localhost'
    12.         , 'username'=>''
    13.         , 'password'=>''
    14.         , 'database'=>'second'
    15.         , 'server_type'=>'sqlite'
    16.         , 'filename'=>'/data/second.dat'
    17.         , 'connection'=>null
    18.         )
    19.     );
    20. ?>
    структура говорит сама за себя. параметр 'connection' устанавливается при подключении и обнуляется при отключении.

    теперь задача становится тривиальной. остаётся лишь вопрос реализации чтения внутри или вне db_fetch_array.
    вариант 1:
    PHP:
    1. <?php
    2. function db_fetch_array ($db_id, $sql)
    3. {
    4.     global $DB_PARAMS;
    5.  
    6.     switch ($DB_PARAMS[$db_id]['server_type'])
    7.     {
    8.     case 'mysql':
    9.         if ($cursor = mysql_unbuffered_query ($sql, $DB_PARAMS[$db_id]['connection']))
    10.         {
    11.             $lst = array ();
    12.  
    13.             while ($a = mysql_fetch_assoc ($cursor))
    14.                 $lst[] = $a;
    15.             mysql_free_result ($cursor);
    16.  
    17.             return $lst;
    18.         }
    19.         break;
    20.  
    21.     case 'sqlite':
    22.         if ($cursor = sqlite_unbuffered_query ($DB_PARAMS[$db_id]['connection'], $sql, SQLITE_ASSOC))
    23.             return sqlite_fetch_all ($cursor);
    24.         break;
    25.     }
    26.  
    27.     db_error_log ($sql);
    28.     return false;
    29. }
    30. ?>
    вариант 2:
    PHP:
    1. <?php
    2. function db_fetch_array_mysql ($conn, $sql)
    3. {
    4.     if ($cursor = mysql_unbuffered_query ($sql, $conn))
    5.     {
    6.         $lst = array ();
    7.  
    8.         while ($a = mysql_fetch_assoc ($cursor))
    9.             $lst[] = $a;
    10.         mysql_free_result ($cursor);
    11.  
    12.         return $lst;
    13.     }
    14.  
    15.     db_error_log ($sql);
    16.     return false;
    17. }
    18.  
    19. function db_fetch_array_sqlite ($conn, $sql)
    20. {
    21.     if ($cursor = sqlite_unbuffered_query ($conn, $sql, SQLITE_ASSOC))
    22.         return sqlite_fetch_all ($cursor);
    23.  
    24.     db_error_log ($sql);
    25.     return false;
    26. }
    27.  
    28. function db_fetch_array ($db_id, $sql)
    29. {
    30.     global $DB_PARAMS;
    31.  
    32.     switch ($DB_PARAMS[$db_id]['server_type'])
    33.     {
    34.         case 'mysql': return db_fetch_array_mysql ($DB_PARAMS[$db_id]['connection'], $sql);
    35.         case 'sqlite': return db_fetch_array_sqlite ($DB_PARAMS[$db_id]['connection'], $sql);
    36.     }
    37.  
    38.     return false;
    39. }
    40. ?>
    на суд внимательного читателя оставим выбор из двух вариантов.
     
  19. Davil

    Davil Guest

    stas_t
    оно-то хорошо, когда его мало.
    Когда такими функциями набит файл весом в 300к не очень весело там копошиться...
    Либо пусть это будет не файл в 300к. Пусть это будет дирректория содержащая 30 файлов.

    Конечно это не очень весомый аргумент, но уж не удержался. Извините =)
     
  20. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    нафик, разделять немедленно.
     
  21. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
    о чём и речь. если реализовывать это на объектах, кода получится ещё больше и разбираться придётся не только с функциональностью, но и с наследованием / скрытием данных / перегрузкой и мало ли что ещё придёт в голову разработчику.
     
  22. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    нет, при правильном подходе разбираться придется намного меньше. Что за разговоры что при структурном подходе не надо разбираться с доступом и сохранностью данных? Просто это ДРУГОЙ подход, и если пытаться писать по прежнему используя классы - станет действительно только хуже. Но это не означает что у все должны так писать и у всех будут такие проблемы.
    ООП УПРОЩАЕТ ЗАДАЧУ, разбивая ее, а не усложняет.
     
  23. Davil

    Davil Guest

    Ну тут уже поздо пить боржоми...
    Вот оно. небольшое заблуждение. Данная мысль абсолютна верна, но для относительно небольших проектов.
    Когда число строк начинает переваливать за второй десяток тысяч - тут уже ООП начинает экономить место и поддерживать структурированность всего приложения в целом.
    Наследование и перегрузка позволяют не плодить однотипные объекты. Сокрытие не позволяет навести хаос и поддерживает порядок в пространстве имен. И в целом получается небольшой "сверхвысокоуровневый язык" оперирования объектами заточенный под необходимые цели, что значительно облегчает дальнейшую разработку и поддержку, сохраняя четкую структуру приложения.
     
  24. Anonymous

    Anonymous Guest

    *задумчиво* а в php 6 namespaces обещают.... *ушел тихонько учить Python*
    Буду ждать - если Python 3 выйдет раньше, чем php 6 - перейду нафик на него...
     
Статус темы:
Закрыта.