ФорумПрограммированиеPHP для идиотов → Статические классы

Статические классы

  • artoodetoo

    Сообщения: 5139 Репутация: N Группа: в ухо

    Spritz 12 сентября 2009 г. 3:08, спустя 3 часа 40 минут 6 секунд

    Цель данной статьи рассмотреть плюсы и минусы написания так называемых "статических классов". Это не баян, а попытка свести воедино всё по данной теме.

    Определения:

    Статическим классом (далее СК) называют класс, содержащий только статические методы и свойства. У него нет конструктора и деструктора, создание экземпляра СК в PHP физически возможно но не имеет смысла.

    Мало ебучий фактор (далее МЕФ) — обстоятельство, не имеющее большого значения в рассматриваемом контексте.

    Плюсы:

    1. Быстродействие. Скорость обращения к статическим свойствам и методам близка к скорости обращения к локальным переменным и простым функциям, то есть в несколько раз быстрее, чем обращение через экземпляр класса. (поправка 2009-09-12: это надо проверить! тыц)

    2. Упрощение и сокращение кода. Нет необходимости создавать экземпляр класса, следить за тем что переменная-объект класса инициирована в нужный момент или что конструктор не вызывается лишний раз. Во многих приложениях бОльшая часть объектов существует в единственном числе, т.е. может (хотя не обязана) реализоваться как Singleton. СК обеспечивает такой функционал "от природы". Подключение классов можно реализовать через автолоадер: не понадобится явно описывать require('path.to.class.unit.php'). Просто упоминаем имя класса, там где надо.

    3. Пространство имен. Конструкции namespace отсутствует в PHP < 5.3, а он еще не начал своё победное шествие. Программист может объявить СК даже в том случае, когда его устроил бы простой набор функций, только чтобы не засорять общее пространство имен. Создавать экземпляр такого класса не требуется!

    Простой пример — "конфигурация приложения" — набор параметров, используемых в различных частях программы.

    Минусы:

    1. Нет конструктора — нет точки в которой мы могли бы выполнить начальную инициализацию свойств класса.

    2. Есть сложности в реализации полиморфизма, т.к. нет экземпляров классов. Вызов метода содержит явное обращение к конкретному классу.

    3. Возможен конфликт с привычными методологиями. Например юнит-тесты требуют уменьшения связанности кода. Модный прием — Внедрение зависимости т.е. передача готовых объектов на вход конструктору тестируемого класса. Вспомогательные объекты должны создаваться где-то там далеко, поэтому в самом тестируемом модуле классы объектов явно не упоминаются.
    А в наших СК нет ни "конструктора", ни "готовых объектов". Класс всегда упоминается явно.

    Workaround:

    Я считаю, что указанные минусы это МЕФ.

    1. Код инициализации можно поместить в модуль класса ниже описания самого класса. Этот код выполнится строго один раз перед первым использованием класса. (поправка: код будет выполнен при подключении модуля, если используется автолоадер — то да, получится перед первым использованием класса)
    А если требуется "ленивая инициализация" — то она делается так же как в не-статических классах, как-то так:

    if (!self::$_initiated) self::_init();


    2. Если рефакторинг под использование СК не получается, а хочется полиморфизма, выкрутимся с помощью

    call_user_func(array('class', 'method'));

    Лишь бы такие заглушки были исключением, а не правилом.

    3. Внедрение зависимостей можно обеспечить, если мы пойдём на такую уловку: классы подгружаем через автолоадер, а пути к загружаемым файлам описываем в файле конфигурации.

    array(
    'ClassA' => 'path.to.my.mocup.class_a.php',
    'ClassB' => 'path.to.my.mocup.class_b.php',

    )

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

    Выводы:

    Мы можем повысить скорость приложения и в некоторых случаях упростить наш код за счет использования СК. Насколько эффективной будет эта методика зависит от контекста и наших способностей.

    (дополнение от 2009-09-12: хаки __get/__set — в СК невозможны)
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 2:19, спустя 23 часа 11 минут 31 секунду

    разрушаю плюсы:

    1. один скл запрос убъет всю макрооптимизацию, у меня на ноутбуке вызов функции класса 10000 раз = 0.2 секунды, (http://94.31.169.103/mygeo/ - benchmark geo engine), не умаю что часто больше чем 10 000 вызовов функций, хотя всяко бывает :) в любом случае это миф.

    2. тот же файл конфигурации, если подходить хардкорно - то есть один конфиг на все, то это да, пиздец конечно. у меня например есть стандартный Config::instance()->get("core.debug") и при ЭТОМ ЖЕ ПОДХОДЕ я могу сделать вот так $config = new Config(dirname(__FILE__)."/local.config.ini"); $debug = $config->get("debug");. так что мнимый плюс я считаю. езе хороий пример - любой синглтон, ведь его можно юзать ОДНОРАЗОВО, но иметь возможность СОЗДАТЬ ЕЩЕ РАЗ (это я так считаю а на приципы ООП и принципы хабра мне глубоко похуй)

    3. для этой цели прекрасно подходит "_" = core_init(); так пхп и жил до объектов.

    Рассуждаю над минусами:

    1. это выход, но это пиздец однозначно.

    2. хорошо что не eval ^^

    3. а для не статических файлов автолоад отменили уже? оО

    4. Это хардкорный метод, не ООП

    есть и плюсы и минусы, плюсы сомнительны, минусы очевидны … человек пришел к ООП, зачем уходить от него? :)

    зы я буду писать как и раньше - говнокодить ^^

    Спустя 54 сек.

    Выводы:

    Мы можем повысить скорость приложения
    тут бы я остановился и добавил что "за счет использования кеширования и опкоде кешеров", но никак не за счет использования СК.
    Сапожник без сапог
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 2:25, спустя 5 минут 22 секунды

    забыл про один большой минус. ИХ НЕЛЬЗЯ ПЕРЕДАВАТЬ АРГУМЕНТОМ ФУНКЦИЙ, ЭТО УЖЕ ПОЛНЫЙ ПИЗДЕЦ, ЭТО НА КОРНЮ УБИВАЕТ РАСШИРЯЕМОСТЬ КОДА И СОЗДАЕТ ДОПОЛНИТЕЛЬНЫЕ ЗАВИСИМОСТИ ОТ КОТОРЫХ ПРИ ДАННОМ ПОДХОДЕ НИКАК НЕ ИЗБАВИТЬСЯ :)
    Спустя 14 сек.
    да я блондинка, у меня даже косички есть
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5139 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 2:47, спустя 22 минуты 42 секунды

    phpdude, спасибо за рецензию, хотя она хуевая

    один скл запрос убъет всю макрооптимизацию

    а я разве говорил, что СК важнее, чем, например, оптимизация запросов и кеширование данных? ну и что с того, теперь забить на все кроме БД?
    накладные расходы на поддержку ООП тоже нехилые, но их можно уменьшить оставаясь на принципах объектного мышления. вот что я хочу сказать.

    Рассуждаю над минусами

    видимо над workaround все-таки :)
    1. это выход, но это пиздец однозначно.

    обоснуй
    2. хорошо что не eval ^^

    далеко не eval ! потестируй - окажется что "правильное" обращение к методу объекта примерно так и делается.
    3. а для не статических файлов автолоад отменили уже? оО

    это демагогия. вернись к постановке проблемы — во многих местах встречал утверждение, что СК убивают возможность модульного тестирования. я этот миф разрушаю.
    а автолоад полезен в любом случае. только с объектами нам никуда не деться от создания объекта. в случае СК не нужно даже это.
    4. Это хардкорный метод, не ООП

    у меня нет пункта 4 так что х.з. может и хардкорный

    Спустя 211 сек.
    забыл про один большой минус. ИХ НЕЛЬЗЯ ПЕРЕДАВАТЬ АРГУМЕНТОМ ФУНКЦИЙ, ЭТО УЖЕ ПОЛНЫЙ ПИЗДЕЦ, ЭТО НА КОРНЮ УБИВАЕТ РАСШИРЯЕМОСТЬ КОДА И СОЗДАЕТ ДОПОЛНИТЕЛЬНЫЕ ЗАВИСИМОСТИ ОТ КОТОРЫХ ПРИ ДАННОМ ПОДХОДЕ НИКАК НЕ ИЗБАВИТЬСЯ :)
    Спустя 14 секунд добавил
    да я блондинка, у меня даже косички есть

    (а еще из них нельзя косички плести)
    может быть их и незачем передавать как аргументы? класс будет виден внутри функции — его незачем передавать аргументом. согласен, что это меняет привычный ход вещей. выбор за программистом.
    Спустя 294 сек.
    пример: ты писал $debug = $config->get("debug");
    предположим у тебя некий объект вызывает метод другого объекта и т.д. тебе переменную $debug надо тащить через каждый вызов в аргументах, чтобы её было видно. или надо бесконечные global везде или использовать мегакрутую конструкцию $GLOBALS['debug'] — вот это пиздец!

    а если ты используешь "конфигурацию" в виде СК — то не надо ничего такого. просто обращаешся типа config::get('my value') или config::MY_CONST
    ιιlllιlllι унц-унц
  • Trej Gun

    Сообщения: 5299 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 2:50, спустя 2 минуты 39 секунд

    2. хорошо что не eval ^^

    это эпилог
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 2:53, спустя 3 минуты 6 секунд

    а я разве говорил, что СК важнее, чем, например, оптимизация запросов и кеширование данных? ну и что с того, теперь забить на все кроме БД?
    накладные расходы на поддержку ООП тоже нехилые, но их можно уменьшить оставаясь на принципах объектного мышления. вот что я хочу сказать.

    даже зенд фреймворк запускается за 0.01 секунды если все его файлы положить в один и использовать опкоде кешер. Такое утверждение устраивает? :) зы читал где то и не раз, можешь погуглить если не веришь, заодно проверишь :)

    1. это выход, но это пиздец однозначно.

    обоснуй

    пропустишь такую строчку в Acl.php и пиздец! по себе знаю, чем больше автоматики - тем меньше ошибок, причем обратная зависимость - геометрическая прогрессия

    2. хорошо что не eval ^^

    далеко не eval ! потестируй - окажется что "правильное" обращение к методу объекта примерно так и делается.

    это я и сам знаю, знал, и знать буду :))

    3. а для не статических файлов автолоад отменили уже? оО

    это демагогия. вернись к постановке проблемы — во многих местах встречал утверждение, что СК убивают возможность модульного тестирования. я этот миф разрушаю.
    а автолоад полезен в любом случае. только с объектами нам никуда не деться от создания объекта. в случае СК не нужно даже это.

    при создании обхекта происходит больше, чем просто "добавление одной строчки в исходник", это как рождение ребенка, чтото ЧИСТОЕ И НЕОСКВЕРНЕННОЕ окружающим миром, и он живет сам по себе, его зовут подработать когда надо, а когда не надо(синглтон). Их может быть целый детский сад, а не один ребенок, в любом случае порождать, просить объекты когда они нужны - правильно. Когда ты используешь голове Class:function() это безликая хуйня, а не класс. замени :: = "_" и получишь еще короче конструкцию, да, кстати можно же и внутри функций юзать

    function test()//  if OOP: function test(Object $o)
    {
        // if !OOP $field = Object::$field;
        // else $field = $o->field;
    }
    красиво просить КОГО ТО ДАТЬ ТЕБЕ РУКУ, а не ЗАПРОСИТЬ КогоТоНеПоймиКого дать тебе НеПоймиЧьюРуку )))))))))))))
    бго %)
    я к тому, что ДА, иногда СТОИТ юзать СК, но НЕ ЗАМЕНЯТЬ ТЕ ЖЕ СИНГЛТОНЫ ИМИ. Конфиг - хуевый пример СК, БД тоже. А вот например в c# есть System.Console - это ахуенный СК.

    4. Это хардкорный метод, не ООП

    у меня нет пункта 4 так что х.з. может и хардкорный

    это я позволил себе дописать



    Спустя 211 сек.
    забыл про один большой минус. ИХ НЕЛЬЗЯ ПЕРЕДАВАТЬ АРГУМЕНТОМ ФУНКЦИЙ, ЭТО УЖЕ ПОЛНЫЙ ПИЗДЕЦ, ЭТО НА КОРНЮ УБИВАЕТ РАСШИРЯЕМОСТЬ КОДА И СОЗДАЕТ ДОПОЛНИТЕЛЬНЫЕ ЗАВИСИМОСТИ ОТ КОТОРЫХ ПРИ ДАННОМ ПОДХОДЕ НИКАК НЕ ИЗБАВИТЬСЯ :)
    Спустя 14 секунд добавил
    да я блондинка, у меня даже косички есть

    (а еще из них нельзя косички плести)

    опять меня наебали в магазине ((

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

    шиворотнавывворот
    Спустя 116 сек.
    artoodetoo,

    пример: ты писал $debug = $config->get("debug");
    предположим у тебя некий объект вызывает метод другого объекта и т.д. тебе переменную $debug надо тащить через каждый вызов в аргументах, чтобы её было видно. или надо бесконечные global везде или использовать мегакрутую конструкцию $GLOBALS['debug'] — вот это пиздец!

    а если ты используешь "конфигурацию" в виде СК — то не надо ничего такого. просто обращаешся типа config::get('my value') или config::MY_CONST


    хочешь разобью в пух и прах ?

    у меня есть COnfig::instance()->get($param);
    хочется короче? да легко

    class Config {
    ..

    publis static function get($param)
    {
    return self::instance()->get($param);
    }
    }

    и юзай наздоровье.
    Спустя 27 сек.
    я же не говорю что СК это плохо, хотя именно СК - плохо, а статические методы - неплохо
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5139 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 3:53, спустя 1 час 10 секунд

    даже зенд фреймворк запускается за 0.01 секунды если все его файлы положить в один и использовать опкоде кешер. Такое утверждение устраивает? :) зы читал где то и не раз, можешь погуглить если не веришь, заодно проверишь :)

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

    ZF во многих местах использует статическое обращение.
    например class ZendX_JQuery — полностью статический класс — такое устраивает? :)))
    подстрока "public static function" в полном ZF встречается примерно 1000 раз

    ага, я знал что ты будешь использовать static для чтения конфигурации :) бинго!

    а я не говорю, что СК — универсально оружие. скорее это полезная методика.
    стОит посмотреть на свой код с точки зрения "а что если зарефакторить на полную статику, может тогда он перестанет быть таким УГ"

    ещё раз спасибо за нападки, они полезны для самотестирования!
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 3:45, спустя 23 часа 52 минуты 6 секунд

    "а что если зарефакторить на полную статику, может тогда он перестанет быть таким УГ"
    интересная идеология))))))))))
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5139 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 3:55, спустя 9 минут 49 секунд


    2. хорошо что не eval ^^

    это эпилог

    некролог :)
    ιιlllιlllι унц-унц
  • Troy

    Сообщения: 2532 Репутация: N Группа: Джедаи

    Spritz 5 сентября 2009 г. 3:56, спустя 26 секунд

    В своём проеке я использую в основном статические классы
    + В любом модуле можно вызвать функцию и не создавать экземпляр класса
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 4:08, спустя 12 минут 17 секунд


    В своём проеке я использую в основном статические классы
    + В любом модуле можно вызвать функцию и не создавать экземпляр класса
    зачем тебе тогда вообще классы? ООП это не просто тупо классы, вы используете их как хранилище …
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5139 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 4:41, спустя 33 минуты 23 секунды

    ООП оперирует понятиями "инкапсуляция" и "наследование". эти штуки относится не к объектам, а к классам.
    а для объектов актуален ещё и "полиморфизм".

    я бы так сформулировал: если в приложении нет массива разнородных обхектов, то его можно переписать на полную статику. если есть такой массив, то можно селать массив свойств (не объектов) + статическую фабрику :)
    Спустя 27 сек.
    можно != нужно

    но выигрыш будет
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 4:44, спустя 3 минуты 6 секунд

    А МНЕ ПОХУЙ!!! У МЕНЯ ПЕРЕСТАЛ БУК ЗАВИСАТЬ!!!!
    Сапожник без сапог
  • Lirck

    Сообщения: 1658 Репутация: N Группа: Джедаи

    Spritz 5 сентября 2009 г. 5:05, спустя 21 минуту 3 секунды

    че лучше, переменные или значения?
  • adw0rd

    Сообщения: 22905 Репутация: N Группа: в ухо

    Spritz 5 сентября 2009 г. 5:09, спустя 3 минуты 36 секунд



    В своём проеке я использую в основном статические классы
    + В любом модуле можно вызвать функцию и не создавать экземпляр класса
    зачем тебе тогда вообще классы? ООП это не просто тупо классы, вы используете их как хранилище …
    он использует их как неймспейсы
    adw/0

Пожалуйста, авторизуйтесь, чтобы написать комментарий!