Pull to refresh

Comments 73

Выигрыш, конечно, на лицо, но слияние двух реализаций функций в одну — сомнительное дело.
Это сделанно в первую очередь для __constructor / __destructor
+ для функций, которые не возвращают результат.
понял не всё. Объясните на пальцах, что делает __autoload?
ru.php.net/__autoload
Достаточно просто описано. И вообще, когда встречаете что-то непонятное загляните сначала в мануал, там много всего интересного, честно :)
__autoload автоматически запускается, когда вы вызываете методы new ClassName или class_exists('ClassName'), но сам запрашиваеммый класс в системе отсутствует.

Документация.
Думал над такой вещью, но не знал, что она есть.

Спасибо.
«Я нихрена не понял что такое паттерны и с чем их едят, и поэтому придумал вот такой велосипед»
Вы действительно нихрена не поняли :)
да-да, в сортах говна не разбираюсь… что поделать..((
Могли-бы просто более конструктивно объяснить.
Задача решается наследованием и полиморфизмом.
Причём здесь паттерны?
И теперь благодаря ему юные дарования сделают парочку своих модификаций данного чуда техники.
Гм. Это что? Попытка реализации множественного наследования на PHP? Зачем?

В принципе сам факт множественного наследования — один из древнейших предметов для холиваров. Иногда это может быть удобно, но в вашем случае скорее всего стоит поискать альтернативные подходы. Например наследование. По-моему им все вышеозначенные проблемы замечательно решаются. Ещё можете посмотреть в сторону паттерна Builder (http://sourcemaking.com/design_patterns/builder).

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

Я наверное что-то не допонимаю.

Спасибо
Я могу объяснить, какие преимущества у моего метода:
1) Нет необходимости каждый раз перелапачивать класс заново при создании. (делать несколько new и вызовов функций)
2) Скорость работы, скорость загрузки.
3) Решаеммые задачи.
4) Возможность extends нескольких классов одновременно.

Минус только один — немного сложнее понять, где ошибка (если она есть).

Перейдя с паттерна Билдера на написанный этот класс, я ускорил работу сервиса с 0.1 до 0.01 секунды на запрос.
Мне кажется, что вы сейчас пытаетесь рализовать анти-паттерн God Object. Т.е. вы пытаетесь запихать весь функционал в некий один объект. Если вернуться к примеру из начала вашего поста, то космическому кораблю должно быть до лампочки, какие у него двигатели, батареи, лазер и прочие девайсы. Он должен легко из них собираться и, при необходимости, реактивные двигатели должны легко меняться на ионные без усилий и потери функционала.

Самая плохая идея — засунуть всё в один объект. Если это делается явно, то код становится невозможно сопровождать, т.к. в нём 5 тысяч строк и какие функции с каими связаны — не разобраться. Конечно, вы несколько разрядили ситуацию разнеся эти куски в отдельные файлы. Теперь по крайней мере функции, имеющие друг к другу какое-то отношение сгруппированы. Но остальные проблемы никуда не денутся.

К примеру, останется проблема конфликта имён. Как быть, если у двигателя, лазера и кофеварки есть метод heatEmergency?

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

В случае же «множественного наследования» просто можно вешаться. Если в космическом корабле есть грузовой отсек, в котором есть транспортный корабль у которого тоже есть двигатель… Когда всё это сидит в одном объекте методов у него будет миллион. И тут я вижу 2 варианта развития событий. Либо у нас будет ничего не говорящий метод heatEmergency и мы будем гадать, что выключится при его вызове — кофеварка, лазер или двигатели на транспортном корабле. Или появятся моструозные методы, типа mainShip_cargoBay_cargoShip_Engine_heatEmergency и вас будут проклинать все, кому придётся дальше работать с этим кодом. Особенно если придётся использовать CargoShip отдельно от главного корабля.

Вот то, что боле-мене сходу пришло в голову. Как видите, основная проблема будет как всегда в наращивании функционала. К тому же, если вам понадобится перенести в другой проект какую-то крупную часть из этого, то вам придётся руками собирать CargoBay, например, из ошмётков, раскиданных в системе. Т.е. если вам нужен не весь корабль, но некая его полноценная часть в случае использования ООП подхода вы просто возмёте и перенесёте нужные объекты. Конечно, там тоже придётся повозится со связями, но по крайней мере они прописаны в явном виде. Если же в вашем способе всё будет сыпаться в один класс, то выделить нужные куски будет гораздо труднее.

Относительно скорости. Мне как-то слабо верится, что разница в создании N дополнительных классов даёт такую нагрузку. Вы, видимо, используя Builder разносили все классы по отдельным файлам? Если да, то что мешает слить их так же в один файл?

На счёт множественного наследования — спорный вопрос. Обычно считается, что если оно стало критически необходимо (по крайней мере в PHP), то структура не правильно спроектирована. Я, кстати, так и не понял, чем вам обычное наследование не угодило? Если грамотно разделить функционал на связанные куски, то любой child логично наращивает функциональность parent'а. Вместе с интерфейсами и абстрактными классами это даёт достаточную гибкость.

Хотя в случае с кораблём конечно нужен Builder.
UFO just landed and posted this here
UFO just landed and posted this here
Забавно. Как раз думаю, не написать ли статейку про mro в Питоне.

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

Мне по мелочи удавалось успешно использовать множественное наследование в Питоне и Перле. Концепт Руби тоже достаточно интересен. Но лично для меня это всё ещё баловство. Интересно, кстати, как сейчас дела с method resolution order в Перле. Очень давно не следил за этим языком. То, как причесали Питон и возможность использовать метаклассы конечно даёт хорошую гибкость. Но как по мне так и путаницы вносится прилично. Впрочем, надо побольше поэкспериментировать.
UFO just landed and posted this here
>> анти-паттерн God Object. Т.е. вы пытаетесь запихать весь функционал в некий один объект.
Вы правы. Я именно этим и озабочен.

Озабочен, потому что у меня при каждом запросе необходимо перегружать сотни объектов.
Вместо этого, я сделал прекомпиляцию ОДИН РАЗ.

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

>> К примеру, останется проблема конфликта имён. Как быть, если у двигателя, лазера и кофеварки есть метод heatEmergency?
Быть в курсе, какие методы используются в объекте (Корабле) и не добавлять существующие — это касается не только функций, а ещё названия классов, и тем более использования средств, которым разработчик пользуется. Я уверен, что человек знает, какие модули есть, каких нет в системе и как ими пользоваться.
Для этого есть средства, (например тоже wiki) в котором описанны все функции, которые уже добавленны и которые БУДУТ добавленны. (рассмотренные ещё на этапе проектирования новых возможностей)

Я использую названия функций с префиксами — energy_heatEmergency, laser_heatEmergency, drive_heatEmergency итд

>> Если в космическом корабле есть грузовой отсек, в котором есть транспортный корабль у которого тоже есть двигатель… Когда всё это сидит в одном объекте методов у него будет миллион.
Это проблемма проектирования, а не реализации.
Именно при проектировании хорошо, чтобы было всё правильно.

>> Относительно скорости. Мне как-то слабо верится, что разница в создании N дополнительных классов даёт такую нагрузку. Вы, видимо, используя Builder разносили все классы по отдельным файлам? Если да, то что мешает слить их так же в один файл?

Я и слил :). Плюс, избавившись от атовизмов билдера.
Но создание сотни объектов на запрос — для проверок и изменения их состояний — это тоже не простая задача, так? И лучше, если будет на создание одного объекта использоваться 1мс, чем 10мс? И вызов каждой функции работы с объектом будет происходить за 1 мс, вместо 5мс.

>> Обычно считается, что если оно стало критически необходимо (по крайней мере в PHP), то структура не правильно спроектирована.
Всё верно говорите. При проектировании для каждого языка, необходимо учитывать его личные свойства.
Я уже говорил, что всё, что получилось — это готовое решение для языка PHP.


Вам правильно заметили — что всё зависит от самой Конструкции проекта. Я об этом упомянул в начале статьи.
Быть в курсе всех методов на большом проекте просто не возможно. Я не найду с ходу такой библиотеки или языка, про которые я мог бы смело сказать «я в курсе всего». Всё забывается, всё разрастается. И крайне не хочется перекапывать весь мануал, если мне понадобится ввести ещё один метод на предмет наличия такого метода в каком-нибудь соседнем классе. Тут никакая wiki не спасёт.

Префиксы пока ещё не монстрообразны? ) А если вам понадобится использовать лазер где-то в другом проекте отдельно от корабля, то придётся писать $laser->laser_heatEmergency()? По-моему это начало моего второго варианта. Через годик появятся префиксы в три этажа.

Проблема проектирования — это я согласен. Но вы, например, можете быть уверены, что завтра заказчик не придёт и не скажет: «Встройте мне вот здесь 2 системы с 3-мя подсистемами и здесь ещё 3»? А возможно и раньше у вас появятся какие-то насущные потребности. Собственно для этого и создавались agile-методы разработки. При постоянно меняющихся требованиях вы должны комфортно себя чувствовать и легко вносить изменения. У вас же получится что любое расширение сведётся к сваливанию дополнительного функционала с гигантский объект. Ваш подход получается более закостенелым. Не зная конкретной задачи я не могу утверждать, что для вас это критично. Но начиная работу над новым абстрактным проектом я бы так делать никогда не стал.

Про проектирование. Если у вас в Builder создаёт сотни объектов, то это дважды неправильное проектирование. Паттернов и методик разных куча. Например, напишите всё в ленивом стиле. Тогдя для того чтобы в запросе дёрнуть лазер вам не понадобится инициализировать двигатель. Вобще я слабо преставляю ситуацию, в которой для обработки запроса приходится инициализировать несколько сотен объектов.
>>> А если вам понадобится использовать лазер где-то в другом проекте отдельно от корабля, то придётся писать $laser->laser_heatEmergency()? По-моему это начало моего второго варианта.

Вы совершенно не поняли суть идеи.

Я не прав, потому что плохо объяснил всё.

Суть идеи НЕ РЕАЛИЗОВЫВАТЬ лазер внутри корабля. Нет!
Суть идеи (я немного в конкретику вдарюсь):
1) Дополнять 'корабль' независимыми друг от друга разработчиками, зависимыми устройствами.
2) Каждое устройство — это отдельный класс.
3) Интерфейс устройств описывается к классе корабля.
4) Файлы должны быть независимыми.

То есть:
Energy.php
//Всё, что связанно с энергией на корабле
class Energy{
var $maxenergy, $incenergy;
}

//Интерфейс энергии
class Ship{
  public $energy;
  function __construct(){
     $this->energy=new energy();
  }
  function energy_get(){...}
  function energy_use(){...}
}

Уберите этот файл из модулей — система продолжит функционировать (если другие устройства не зависят от energy_get/energy_use). Просто на корабль невозможно будет поставить устройство Energy.

Я предложил метод, который упрощает разработку, НО не настаивает в том, чтобы лепить классы в ОДНО.
Как вам сказать. Лично по-моему то что вы сейчас написали — это как раз попытка реализовать Builder. Так что вы уж определитесь — валить все функции в один класс или использовать этот класс как оболочку, которая генерирует для себя всё необходимое.
А о композициях и как с ними работать мы даже и не слышали…
Пример не очень верный… Но Лазер можно убрать из игры вообще, простым удалением файла.
Не нравится пример, пользуйтесь $ship->energy->get()

class Energy{
  var $maxenergy, $incenergy;
  function get(){...}
  function use(){...}
}

//Интерфейс энергии
class Ship{
  public $energy;
  function __construct(){
      $this->energy=new energy();
  }
}
Быть в курсе, какие методы используются в объекте (Корабле) и не добавлять существующие — это касается не только функций, а ещё названия классов, и тем более использования средств, которым разработчик пользуется. Я уверен, что человек знает, какие модули есть, каких нет в системе и как ими пользоваться.


Предлагаете мне заучивать документацию? Или хотите что бы я тратить треть своего времени на придумывание очевидных названий для методов? Интересно, через сколько недель у нас закончаться в прокете имена и начнем выдумывать что-то вроде qu1t, ex1t?

Теперь по существу.

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

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

Вы совершенно не понимаете принцип, с которым я работаю и зачем мне внедрять несколько лишних (по вашему мнению) методов в объект. Я не буду вам этого объяснять — потому что это не имеет значения без понимания принципов построения моего игрового мира.
Значение имеет лишь то, что класс mods позволяет работать как с пересечением модулей, так и без них. Пользуйтесь этим, как пожелаете.
UFO just landed and posted this here
Не сталкивался с механизмом Эвентов в php. (только error/warning-events)

Подскажите где посмотреть?
UFO just landed and posted this here
У меня есть реализованная система Эвентов.
Вы рассказываете о ней, как о чём-то, что решит все мои проблеммы, но это не так.

Делать кстати, через Статик (в PHP)- так это вообще убожество — лучше предложите просто через простые функции реализовать это — будет выйгрыш в более внятных названиях.
UFO just landed and posted this here
Простой пример статика:
mods()->
вместо
modules::singleton()->
Эвент:
energy()->get_ship_energy($ship)
Мой метод:
$ship->get_energy();

Что нагляднее?
Что быстрее выполнится?
UFO just landed and posted this here
Короче уехали мы не туда.
Я понимаю, что вы называете эвентами.

Класс Эвентов на PHP (особенно в реализации call_user_func) будет вызываться в несколько раз дольше, чем готовый, собранный класс.
UFO just landed and posted this here
Как вы перебор вызовов функций С ПАРАМЕТРАМИ повесите на якорь?
UFO just landed and posted this here
Не уверен, что целесообразно всегда передавать array в сложных проектах.
Наглядность пропадает.

function name($input){
  if ($input[0]){
    str_replace($input[1], $input[2])…
  }
}
UFO just landed and posted this here
Я уже говорил о производительности.

Я работал с системой Эвентов — после данной модификации:
1) код стал намного чище
2) система ускорилась в 3 раза.
UFO just landed and posted this here
Я в курсе — у самого такая реализация есть. Я о другом…
И вот, спустя 10-15 лет, вы придумали аццкий вилосипед, который был в прародителе, который называется Autloload.

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

Из серии «Дорогой дневничок, сегодня я придумал машину времени»
Чем мне __autoload поможет в том, чтобы объединять классы из разных файлов?
Оригинальная у вас реализация шаблона «Одиночка»… :-)

PS По уму, надо писать удобный код и для модификации и для разработки, и перед выкладыванием на сайт, прогонять его через phing или maven или ant, или любую другую систему (может даже свою) систему сборки…

В чём оригинальность?
Посмотрите пожалуйста сами

www.google.ru/search?q=php+pattern+singleton

Одно из составляющих «шаблона одиночка» — объектная модель, что подразумевает класс, а не функцию! вообщем найдите сами десять различий…
Я не вижу смысла использовать в PHP статический класс вместо функции…

$mod=modules::getInstance() — я считаю, что это идиотизм. (касательно PHP)
$mod->cache('a.php');
$mod->include('a.php');

Вариант выглядит намного яснее:
mods()->cache('cache.dat')->phpcache('cache.php')->include('a.php')->include_modules();
Либо:
$mod=mods();
$mod->cache('a.php');
$mod->… ну итд

Если вы мне объясните, какое преимущество в «объектной моделе» (касательно PHP), я приму иную точку зрения. А «Так НАДО» — это, простите, тупизм.
p.s. Если хотите, могу не называть это singleton — смысл не потеряется. :)
Я не хочу вас убеждать в том что объектная модель лучше, я говорю о том, что это НЕ ШАБЛОН ОДИНОЧКА (SINGLETON). :-)

Кажется, мы просто не поняли друг друга :)

PS Я знаю эти войны ООП с процедурным программированием и не хочу в них участвовать, иногда я тоже отдаю предпочтение процедуре, хотя мне нравится ООП в целом :)
Хорошо.
Значит это не Синглтон :)
1000-й в рейтинге хабралюдей… Можете напиться ;)
Вы это сейчас мне?

Если мне, то я не особо слежу за событиями в карме… Лишь бы не был забанен :-)

Так что попойка отменяется :)
Идиотизм, да?

$first = mods();
$second = new MyFooModule();
$third = clone $first;

Ахуенный синглтон. Так держать!
Если я правильно понял, это что-то типа mixin-ов. Жаль такой возможности в PHP нету.
Это не что-то типа миксинов… это жесть в виде Blob-объекта, столкнувшись с которым понимаешь, что насилие — это не так уж и плохо.

А миксины вроде обещали в 5.3
дадад, странная и опасная реализация микшенов.
мне кажется все это работать быть динамически, а не путем формирования файлов. если уж нужна такая возможность, лутше использовать classkit/runkit, жаль что эти модули слабо разбиваются и не добавляется подобный функционал в ядро.
Динамика в несколько раз медленее. Я уже говорил, что не от хорошей жизни это было реализованно.
кстати наоборот, в комбинации с eaccelerator использование lazy loading ускоряет загрузку сайта, а склеивание всего кода в один замедляет.
dklab.ru/chicken/nablas/49.html
Подключение всех файлов по одному, eAccelerator включен: 435 мс. Занято 15 М кэш-памяти под байт-код.
Включение одного большого слитого файла, eAccelerator включен: 42 мс. Занято 31 МБ кэш-памяти под байт-код.
Вы не правы. Lazy loading — это не когда вы загружаете весь свой фреймворк маленькими файлами, а когда файлы с классами подключаются по мере надобности.

790 PHP-файлов общим объемом 4.9 МБ — скажите, вам прямо на каждой странице вашего сайта весь этот код нужен? В том то и дело, что с такой архитектурой вы загружаете каждый раз много лишнего кода, на который тратиться время парсера и виртуальной машины. Судя по объему, я почти уверен, что на каждый запуск единовременно вам требуется не более 5-10 процентов кода, для 10 процентов получаются те же самые миллисекунды + 1.5 М вместо 31 М памяти (приблизительно).

Я вообще что-то с трудом представляю ситуацию, когда под байткод может потребоваться 31 М, и данное дело нельзя оптимизировать.
В моём случае, в едином загружаемом файле будут только классы, которые используются для работы.
Ну это только потому, что вы ZF используете. Обратите свои взгляды на Yii, если написание своего фреймворка вам кажется предосудительным занятием.
Хм, дочитал до конца вашу статью и нашел такие строки:
Заметьте также, что мы подключали весь Zend Framework. В реальных скриптах объем кода будет сильно меньше, т.к. обычно для работы требуется лишь незначительная часть ZF.

Так все-таки, ВЕСЬ фреймворк, или только классы для работы?
Вы спутали статьи на dklab и здесь.
Они разные и написанны разными авторами.

Скрипт, приведеный здесь, реализует динамическое кеширование необходимых библиотек для работы сайта. Если сайт использует SQL — то он будет объеденен в единый файл. Если не использует — то не будет.
Простите, но спутал, очевидно, не я — перечитайте первые два комментария ветки.
Я наоборот пытаюсь отойти от порочной практики «все-в-одном» и разделять даже целые классы на мелкие составляющие. Например, у меня реализуется подсистема кеширования. Она сотоит, по сути, из двух компонентов — один отвечает за чтение кеша, а другой за запись, обработку и сохранение метаданных. Так получается, что второй компонент занимает 3/4 подсистемы кеширования, однако его функционал не нужен для тех страниц, которые уже закешированы. Как результат, целиком cache.php загружается, например, 15 миллисекунд, а только та его часть, которая отвечает за чтение, примерно 4 миллисекунды. Я разделяю класс Cache на Cache и CacheHelper — второй класс автоматиечски подключается (include), когда вызываются функции типа Cache::write (фактически, эти функции служат прокси — они выглядят примерно так:
class Cache {

function write(...){
include_once('CacheHelper.php');
CacheHelper::write(...);
}
}

В итоге удается сэкономить довольно много времени выполнения скриптов, практически не меняя исходного кода конечного скрипта — он как вызывал Cache::read и Cache::write, не задумываясь о наличии CacheHelper, так и продолжает.

В случае с вашим же подходом, как я понимаю, CacheHelper будет в любом случае включаться в скрипт, независимо от того, закеширован уже результат или нет.
Всё верно говорите. Полность разделяю ваш подход.

В моём случае, произойдёт тоже самое, как вы и описали. Хотя, тут уже многое зависит от проекта и реализации.
Sign up to leave a comment.

Articles