Типажи в PHP: хорошо это или плохо?

Автор оригинала: Callum Hopkins
  • Перевод
Типажи в PHP: хорошо это или плохо?

В марте 2012 года был анонсирован релиз PHP 5.4. В этой версии должно было появиться множество интересных нововведений, так что разработчики ждали его с нетерпением. Пожалуй самой ожидаемой особенностью стали типажи (traits). Еще до релиза, Shameer C написал замечательный обзор возможностей, которые дают нам типажи в PHP. Я настоятельно рекомендую вам ознакомиться с этой статьей, так как моя статья предполагает наличие у вас базовых знаний по типажам и понимание их работы.

Сообщество разработчиков PHP приняло типажи, в основном потому, что они уже были реализованы в других популярных языках программирования, например Java, C++ и Python. Кроме того, преимущества типажей были хорошо разрекламированы разработчиками, которые вставляли свои пять копеек, касательно того, как типажи помогут улучшить любой проект, особенно как замена наследования. Но так ли хороши типажи на самом деле? Помогут ли они повысить уровень PHP разработчиков, или же это просто очередная причуда?


Типажи в PHP это плохо


Добавление типажей в основном мотивировалась тем, что их использование поможет уменьшить дублирование кода. Так же, они могут упростить поддержку кода, сделать его чище.

Большинство разработчиков, безусловно, приветствовало такую возможность, однако многие ведущие разработчики опасались, что типажи будут использоваться не по назначению. Одним из таких разработчиков является Энтони Феррара, опасения которого развились настолько, что он провозгласил типажи следующей наиболее злоупотребляемой особенностью языка, наряду с eval и константами. Но перед тем как Энтони сделал столь резкие выводы, он привел очень интересный довод: типажи на самом деле являются коллекцией примесей, которые практически не имеют состояния. Реализация типажей в PHP позволяет им иметь состояния, так что по сути типажи в PHP это примеси. Из этого простого факта возникает вопрос об истинной цели введения типажей в PHP. Нет никаких объяснений того, почему типажи обрабатываются как обычные примеси, а не как примеси без состояний, какими они в конечном счете и должны быть.

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

Так же возникает вопрос касательно интерфейсов. Многие разработчики имеют лишь смутное представление о различиях между типажами и интерфейсами; вы можете повторно использовать как типажи так и интерфейсы, так же, как и в случае с инетфейсами, вы можете наследовать типажи друг от друга. Являются ли типажи чем то новым для PHP, или же это просто обновленные интерфейсы?

Типажи в PHP это хорошо


Несмотря на поднятые вопросы, типажи это хорошо для PHP. Они позволяют нам реализовать множественное наследование (как известно ключевое слово extends позволяет реализовать только одиночное наследование).

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

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

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

При помощи типажей, напротив, множественное наследование может быть реализовано. Как показал Shameer в своей статьей по использованию типажей, вы можете использовать несколько типажей внутри класса. Джон Сквиб в своем примере использования типажей 2011-ого года использовал несколько типажей для реализации множественного наследования.

Большинство программистов считают множественное наследования злом, указывая на "проблему ромба", и утверждают что одиночное наследование доставляет меньше головной боли. Но дело то не в том, что непрактично использовать множественное наследование в PHP, а в том, что такая возможность существует. В свете множества публичных высказываний против PHP, это становится особенно важным. В качестве подтверждения просто загуглите «Не используйте PHP». С появлением возможности использования множественного наследования, PHP стал более вызывающим, дорогим и приемлемым языком программирования, а не только «самым распространенным WEB языком». Я нахожу это довольно утешительным фактом, когда разработчики, использующие C++, Java или Python, пытаются принизить PHP в силу слабой поддержки языком стандартных методов программирования.

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

Заключение


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

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

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



От переводчика: замечания по переводу прошу присылать в личку.
Поделиться публикацией

Похожие публикации

Комментарии 140

    +15
    Видимо статья про traits? Я долго ломал голову над тем, что такое типажи, пока не сходил по ссылкам.
      +1
      А еще я в теги добавил, на всякий случай. Но это не отменяет того факта что трейты это типажи. На всякий случай пометил в начале статьи.
        +4
        Я б «типажи» на «трейты» все же заменил. Вы же composer композитором не называете
          +3
          Ну тут можно поспорить. Общепризнанное названия такого рода структур все же типажи (покрайнемере так их называют в тех же C++, Java). А вот composer Это уже имя собственное. Я не филолог, просто о типажах я впервые услышал именно из C++ и именно в таком варианте названия.
      +2
      Пусть это будет называться как угодно. В любом случае я подпишусь — да, это то, чего мне постоянно не хватало (множественное наследование). Да. наверняка сейчас есть сложности в поиске откуда ноги растут, но наверняка появятся новые методы мониторинга классов, и проблема исчезнет. Но то, что они это сделали уже сейчас — реально прорыв!
        +3
        А можете накидать пару-тройку примеров, когда их Вам не хватало?
          –1
          Основной момент, это именно множественная наследовательность. попробую объяснить на пальцах.
          Вот у нас есть класс Животное (буду по русски писать, чтобы не переводить тем, кто не знает англ.)
          Есть классы Домашнее_животное и Дикое_животное (производные от Животное).
          Есть классы Кошка, Олень.

          Сейчас приходится наследственность Собаки и Кошки выглядит так:
          class Домашнее_животное extends Животное{}
          class Кошка extends Домашнее_животное{}

          Так же и Олень
          class Дикое_животное extends Животное{}
          class Олень extends Дикое_животное{}

          И этих последовательных расширений может быть довольно много.
          В предложенном же методе можно так писать

          class Кошка{
          use Животное, Домашнее_животное;
          }

          А если исходных классов штук 20? Можно довольно гибко всякие кастомные классы получать. Допустим
          class Кошка{
          use Животное, Домашнее_животное, Кошачьи;
          }
            0
            Не самый удачный пример.

            Во первых зачем use Животное и Домашнее_животное если Домашнее_животное уже Животное.
              0
              Просто я скорее всего двусмысленно выразился здесь:
              Есть классы Домашнее_животное и Дикое_животное (производные от Животное).

              На самом деле эти классы мы не делаем сразу extends. Их мы наследуем тогда, когда классическим образом идет разработка.
              Сейчас приходится наследственность Собаки и Кошки выглядит так:
              class Домашнее_животное extends Животное{}
              class Кошка extends Домашнее_животное{}

              В предлагаемом же варианте эти классы не расширяют сразу базовые классы. То есть весь код выглядит так:
              trait Животное{}

              trait Дикое_животное{}
              trait Домашнее_животное{}
              trait Кошачьи{}
              trait Парнокопытные{}
              и т.д.

              class Кошка{
              use Животное, Дикое_животное, Кошачьи;
              }
                0
                Отличный метод отстрелить себе яй ногу.
              –3
              И зачем

              Есть классы Домашнее_животное и Дикое_животное (производные от Животное).


              Не проще ли обойтись одним классом Животное с полем boolean дикое?
              Аналогично, есть сомнения в необходимости остальных перечисленных классов.
                0
                Может тогда привести в пример несколько тысяч строк кода того же MODX-а, чтобы показать, зачем перешли от использования просто классов к абстрактным, и какую множественное наследование может добавить гибкость?
                Это очень простой пример и понятно дело, что далеко не все идеально. Но его не надо буквально воспринимать, а надо просто идею видеть.
                  0
                  О да,

                  fossies.org/dox/modx-2.2.6-pl/classxPDOObject.html
                  fossies.org/dox/modx-2.2.6-pl/classmodAccessibleSimpleObject.html

                  И это вы считаете образцом хорошего ООП дизайна?
                    –1
                    Пусть меня запинают минусами, но xPDO — одно из самых гениальных решений, с которыми мне приходилось работать. И я не просто любитель xPDO, а очень хорошо знающий его, потому знаю, о чем говорю.
                      +4
                      Дело не в xPDO (Это же что-то типа библиотеки ORM для PHP?). А дело в архитектуре вашей CMS.

                      Почему так много классов наследуют объект работы с БД? Где инкапсуляция? Где абстракция от ORM слоя? Почему modEvent, modActiveUser, modScript и т.д. могут невозбранно лезть в БД? Чем это лучше олдового кондового пхп где можно было в любом месте делать mysql_query?

                      Если весь этот ужас приправить примесями, боюсь даже представить, насколько усугубится этот бардак.

                        –2
                        Многие не понимают смысла xPDO как раз потому, что думают, что весь их смысл только во взаимодействии с DB. Но это не так. Все взаимодействие с БД выполняется на уровне пары классов, основной из которых xPDOQuery. Именно он выполняет взаимодействие с DB посредством PDO, расширением которого и является xPDO.

                        Все же производные от xPDOObject — это не просто объекты для взаимодействия с DB, а полноценные самостоятельные объекты, при чем отлично расширяемые. Но как это часто бывает в веб-проектох, эти сущности хранят свою информацию в базах данных.

                        К примеру возьмем класс modUser. Понятно дело, что все записи пользователей хранятся в DB. И допустим, мы хотим получить определенного пользователя. Мы выполняем $user = $modx->getObject('modUser', $id); Но в данном случае мы получим не просто данные пользователя, а именно объект пользователя. То есть xPDO получит данные пользователя, и вернет соответствующий объект с этими данными. Если бы нам нужны были только данные пользователя, мы могли бы просто выполнить запрос и получить данные, при этом возможно полностью без класс modUser.

                        Но работа с таким объектами реально удобна. Получил объект, выполнил какие-то действия с ним, изменил какие-либо его значения, и сохранил его $user->save(); При этом эти объекты могут быть наделены своими уникальными методами, и можно влиять и на все процессы, в том числе установки и чтения переменных, удаления, сохранения и т.п. Но довольно сильная сторона — возможность расширения базовых объектов так, чтобы использовать таблицу исходного объекта. Таким образом мы и функционал расширяем, и базу данных не раздуваем, и за айдишниками не следим. Довольно наглядно про это написано здесь.

                        Плюс к этому очень мощная штука — связи объектов. То есть я на уровне ключей объектов могу прописать связи, и прописать зависимости (к примеру, удалять зависимый объект или нет). И в дальнейшем, к примеру, вот так работать: $profile = $user->getOne('Profile');
                        При этом вообще не приходится следить за первичными и вторичными ключами, именами колонок и т.д.

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

                        Ну и довольно большим аргумент будет вот этот топик с видюшкой: community.modx-cms.ru/blog/social-engine/9493.html
                        Аргумент: на все про все написано менее тысячи строк кода. Это при том, что там очень много всяких проверок, управление из админки и т.п.
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            Я не ORM отстаиваю, а говорю о реальной сути xPDO и его плюсах.
                            Если хотите намекнуть на то, ORM — это не по религии, и что pure SQL — это все, и я должен только его проповедовать, то не стоит утруждаться. Я год весь биллинг сотовой компании поддерживал, и с Ораклом научился работать на год раньше, чем с мускулом познакомился, и на чистом SQL, и PL/SQL пишу запросы и т.п. очень хорошо, чтобы что-то с чем-то сравнивать.
                            • НЛО прилетело и опубликовало эту надпись здесь
                                –3
                                Ваше право толковать все так, как вам хочется. И честно — феолетово, что вы там думаете об ORM. Насмотрелись уже всяких противников ORM. Пишите на чем хотите.
                                  +3
                                  Поддержу nateless — если отбросить детали типа имен классов, то вы говорите о преимуществах практически любой ORM. А вот чем xPDO лучше, например, моей любимой Doctrine или, скажем, Propel — ни слова не увидел.
                                    –3
                                    Я не говорю, чем оно лучше. Я показываю его суть, плюс связку с MODX.
                                    А вот чем xPDO лучше, например, моей любимой Doctrine или, скажем, Propel — ни слова не увидел.
                                    Не работал ни с одной, ни с другой. Но посмотрел этот мануал: propelorm.org/documentation/04-relationships.html
                                    В глаза брасается вот это:
                                    $author = new Author();
                                    $author->setFirstName("Leo");
                                    $author->setLastName("Tolstoy");
                                    // no need to save the author yet
                                    
                                    $publisher = new Publisher();
                                    $publisher->setName("Viking Press");
                                    // no need to save the publisher yet
                                    
                                    $book = new Book();
                                    $book->setTitle("War & Peace");
                                    $book->setIsbn("0140444173");
                                    $book->setPublisher($publisher);
                                    $book->setAuthor($author);
                                    $book->save(); // saves all 3 objects!
                                    

                                    А что, все работает только на каких-то уникальных прописанных методах типа ->setTitle() или setIsbn()?
                                    Разве нельзя просто $book->set('title', $title); и $book->set('Isbn', $Isbn);?
                                    Или так?
                                    $book->fromArray(array(
                                        'title' => $title,
                                        'Isbn' => $Isbn,
                                    ));
                                    

                                    То есть оперируя просто именами переменных, а не создавая уникальные методы?

                                    И вот это: $book->setAuthor($author); (Добавляет объект)
                                    Разве нельзя типа $book->addOne($author); и чтобы ORM-ка сама разобралась что это за объект и куда его сунуть?
                                      +2
                                      Ручками эти методы писать не нужно — кодогенераторы по схеме БД или, емнип, генерация схемы по чему-то

                                      Лично мне отдельные акцессоры для каждого поля больше нравятся — автодополнение в IDE, phpdoc, статический анализ и прочие плюшки «статической» типизации.

                                      setAuthor предполагает что связь один к одному. addOne этого не предполагает. По имени функции я не могу преположить, что произойдт если я сделаю два вызова подряд если в схеме связь задана 1:1
                                        –2
                                        Ручками эти методы писать не нужно — кодогенераторы по схеме БД или, емнип, генерация схемы по чему-то
                                        Мне этого уже достаточно для того, чтобы сказать, что xPDO лучше представленных ORM-ок, так как нет универсальности, а код разрастается.

                                        Лично мне отдельные акцессоры для каждого поля больше нравятся — автодополнение в IDE, phpdoc
                                        В xPDO никто не ограничивает в этом. Своему объекту можно сколько угодно собственных методов прописать.
                                        function setTitle($title){
                                            return $this->set('title', $title);
                                        }
                                        

                                        setAuthor предполагает что связь один к одному. addOne этого не предполагает.
                                        Как раз очень даже предполагает. И это четко описывается в модели объекта. Если же для него связь прописана один-ко-многим, то используется метод ->addMany(), при чем в таком случае метод ->addOne() для него не выполнится.
                                          +1
                                          Универсальные методы есть, но я их ни разу не использовал. Или обычные акцессоры или тупо публичное свойство без всякой магии.

                                          Я должен ручками писать акцессоры для каждого из полусотни полей?

                                          Не знаю как у вас предполагает. Для меня addOne предполагает добавить одну (из многих) запись за раз, а addMany — сразу много (aka пакетное добавление). Имхо, имя метода должно говорить основные концепции без анализа кода класса. setAuthor мне говорит, что автор может быть только один и этим методом он будет установлен (или перезаписан, если уже есть), а addAuthor (или authors->add) мне говорит, что авторов может быть много, а этим методом автор будет добавлен (неоднозначность возникает только если такой автор уже есть, но обычно хватает беглого взгляда на код, чтобы выяснить набор это или множество)

                                            0
                                            Я должен ручками писать акцессоры для каждого из полусотни полей?
                                            В том-то и дело, что в xPDO этого вообще не требуется. Я всего-лишь показал, что при желании свои методы добавить всегда можно.

                                            По поводу имен методов вообще не буду спорить.
                                              0
                                              Пускай не требуется, но я желаю — ручками должен писать или есть стандартная тулза, которая проанализирует метаданные и «напишет» мне все эти методы?
                                                0
                                                Какие именно «эти»? Хотите данные для колонки указать/изменить, выполнили $object->set($field, $value);
                                                Есть массив данных и хотите все их «скормить» объекту? Пожалуйста. $object->fromArray($data);
                                                Все данные объекта вы можете получить через $object->toArray() или конкретно $object->get($field).
                                                При этом при сохранении он сохранить только те колонки, которые у него прописаны в мета.

                                                Хотите объект добавить, тоже не вопрос. $object->addOne($anotherObject) или если связь один ко многим $object->addMany($objectsArray);

                                                А свои методы пишутся только для уникального функционала. К примеру я хочу обрабатывать особым способом установку значения для какого-то поля. Тогда я в классе объекта пропишу.
                                                function set($field, $value){
                                                    switch($field){
                                                         case 'author':
                                                              $value = "Mr.(Ms.) {$value}";
                                                              break;
                                                    }
                                                    return parent::set($field, $value);
                                                }
                                                
                                                  0
                                                  Я привык даже для самых простых таблиц с самой простой логикой писать отдельный класс контейнер. Так проще расширять. В конечном счете большинство ORM-ок так или иначе используют PDO, но добавляют множество своих приятных люшек. Не вижу смысла использовать просто PDO. Если у вас все настолько упирается в производительность, то пожалуйста, пишите на PDO, но это один случай из ста.
                                                    0
                                                    xPDO — это не PDO, а его расширение. И оно идет со своими плюшками, и да, для каждой таблицы используются свои объекты, и да, их можно расширять, и они могут расширять друг друга.
                                                      0
                                                      Простите, надо выспаться. Я думал x это название драйвера.

                                                      И все равно я не вижу явных преимуществ xPDO над Doctrine.
                                                        +1
                                                        Каждому свое, и свое не каждому.
                                                          0
                                                          Дело в том, что xPDO, хоть и самостоятельная библиотека, тем не менее является неотъемлемой частью MODX Revolution. Это по сути их собственная разработка.
                                                          Так как MODX — мой основной фреймворк, то логично, что я и буду использовать xPDO.
                                                            0
                                                            Я как познакомился с Doctrine 2, так вообще ни в одной ORM не только на PHP, но и на Ruby преимуществ не вижу :)
                                                              0
                                                              xPDO в купе с MODX — это не только ORM, это Acl, источники медиа (не только локальная файловая система, но и облака Amazon3), система пакетов, репозитории, офигенная админка и многое-многое другое. Это программный комплекс.

                                                              Просто посмотрите вот этот топик для примера: community.modx-cms.ru/blog/documentation/9611.html
                                                                0
                                                                Видимо отстал от ModX — когда в последний раз крутил (лет 5 назад, наверное, точно не меньше трех), то Drupal мне показался и мощнее, и проще.
                                                                  0
                                                                  Лет 5 назад еще даже не Evolution, а более ранняя ветка 0.9 была. Это принципиально разного уровня платформы.
                                                                    +1
                                                                    Крутил в курах ModX где-то с год назад. Как раз таки эволюшен. Мне не понравилось. Да и в моих проектах она не применима. Разве что для сайтов визиток или других шаблонных сайтов.
                                                                      –1
                                                                      Evolution уже как года два не развивается командой MODX (если не считать патчи безопасности).
                                                                      Revolution — принципиально другая платформа. Могу вас заверить, что я эксперт MODX мирового уровня (не побоюсь таких громких слов) и являюсь MODX Ambassador в Москве.
                                                                      Разница этих веток настолько принципиальная, что в сообществе даже раскол произошел, и не только в России. Наш community.modx-cms.ru — по большей степени по Revolution.
                                                                      modx.im (отколовшийся) — по Evolution.

                                                                      Функционал, который Revolution дает «из коробки» несоизмеримо бОльший по сравнению с Эво. А система пакетов позволяет проекты разрабатывать 100% модульно.

                                                                      К слову, любой желающий, кто в Москве, может прийти к нам в гости, и я лично отвечу на интересующие вас вопросы и продемонстрирую возможности MODX Revolution.
                                                                  +2
                                                                  Пример ужасен. Я по работе использую Symfony и для нее наваяли сервисов/бандлов для интеграци с AWS что не счесть. Не думаю что серьезный проект стоит писать на MODx.
                                                                    0
                                                                    Вот это ужасно?
                                                                    $id = 2;    // ID медиасурса
                                                                    // Получаем объект
                                                                    $source = $modx->getObject('sources.modMediaSource', $id);
                                                                    // Инициализируем 
                                                                    $source->initialize(); 
                                                                    $url = $source->getObjectUrl('images/image.png');
                                                                    

                                                                      +2
                                                                      Вот это ужасно:
                                                                      public function initialize() {
                                                                          parent::initialize();
                                                                          $properties = $this->getPropertyList();
                                                                          if (!defined('AWS_KEY')) {
                                                                              define('AWS_KEY',$this->xpdo->getOption('key',$properties,''));
                                                                              define('AWS_SECRET_KEY',$this->xpdo->getOption('secret_key',$properties,''));
                                                                              /* (Not needed at this time)
                                                                              define('AWS_ACCOUNT_ID',$modx->getOption('aws.account_id',$config,''));
                                                                              define('AWS_CANONICAL_ID',$modx->getOption('aws.canonical_id',$config,''));
                                                                              define('AWS_CANONICAL_NAME',$modx->getOption('aws.canonical_name',$config,''));
                                                                              define('AWS_MFA_SERIAL',$modx->getOption('aws.mfa_serial',$config,''));
                                                                              define('AWS_CLOUDFRONT_KEYPAIR_ID',$modx->getOption('aws.cloudfront_keypair_id',$config,''));
                                                                              define('AWS_CLOUDFRONT_PRIVATE_KEY_PEM',$modx->getOption('aws.cloudfront_private_key_pem',$config,''));
                                                                              define('AWS_ENABLE_EXTENSIONS', 'false');*/
                                                                          }
                                                                          include_once $this->xpdo->getOption('core_path',null,MODX_CORE_PATH).'model/aws/sdk.class.php';
                                                                      
                                                                          $this->getDriver();
                                                                          $this->setBucket($this->xpdo->getOption('bucket',$properties,''));
                                                                          return true;
                                                                      }
                                                                      


                                                                      И еще, xpdo включает в себя еще и DI контейнер? Как-то нелогично.

                                                                      В моих проектах получить путь можно так:
                                                                      $repository = $this->getDoctrine()->getManager()->getRepository(Acme:Attachment);
                                                                      // получаем объект
                                                                      $attachment = $repository->find($id);
                                                                      // сервис, который отвечает за логику работы с путями
                                                                      $pathResolver = $this->get('acme.path_resoler');
                                                                      $uri = $pathResolver->getFileUri($attachment->getUri());
                                                                      


                                                                      А уже вся логика для работы с файловой системой, использовать AWS или же что-то другое ложится на плечи этого простого сервиса. И настройки все он получает через DI при инициализации.

                                                                      Подход по сути отличается только реализацией, но не сутью.
                                                                        0
                                                                        ну так и вы бы показали листинги методов getManager(), getRepository() и т.п.
                                                                        То, что вы процитировали, это часть объекта, обеспечивающего взаимодействие с облаком AmazoneS3. И это внутренности. Программисту же достаточно использования только этого.
                                                                        $id = 2;    // ID медиасурса
                                                                        // Получаем объект
                                                                        $source = $modx->getObject('sources.modMediaSource', $id);
                                                                        // Инициализируем 
                                                                        $source->initialize(); 
                                                                        $url = $source->getObjectUrl('images/image.png');
                                                                        

                                                                        При этом просто смена $id может в итоге повлиять на то, какой объект-провайдер будет инициализирован, будь то файловая система, AmazoneS3 или какой-то другой свой. И от этого этот код не поменяется. Мы выполним все тот же $url = $source->getObjectUrl('images/image.png');
                                                                    +1
                                                                    Получаем обсолютный путь
                                                                    Это пять!
                                                                      –4
                                                                      Мы не на уроке русского языка, и я не филолог.
                                                                        +3
                                                                        Это обычная норма русского языка, тем более для специалиста с техническим или физмат образованием.
                                                                          –1
                                                                          У меня нет образования, кроме общего среднего.
                                                              0
                                                              xPDO — это ORM по паттерну ActiveRecord, если не ошибаюсь.
                                                                –2
                                                                Ошибаетесь.
                                                                PDO (PHP Data Objects) — это php-библиотека (и объект) для взаимодействия с различными базами данными, пришедшая на замену классическим _mysql и т.п. Наверняка же знаете, что методы типа mysql_connect() и т.п. уже устаревшие.

                                                                xPDO — это собственная библиотека фреймворка MODX, которая расширяет объект PDO (чисто чтобы обеспечить работу с БД), но сразу имеет в себе и несколько базовых объектов типа xPDOObject, xPDOSimpleObject и т.п.
                                                                Плюс весь MODX Revolution построен на этих xPDO-объектах. Тот же пользователь modUser — это в итоге дочерний от xPDOObject.

                                                                Все это в купе с отличной админкой, написанной с использованием ExtJS (которая так же славится своей кастомизацией), дает очень мощный инструментарий в руки.
                                                                  +2
                                                                  Причем тут админка?

                                                                  PDO — абстракция над базой.
                                                                  xPDO — ORM использующая PDO и реализующая паттерн ActiveRecord (о чем к слову даже в документации говорится). Так что не вижу ошибки.
                                                                    0
                                                                    Спасибо за поддержку. А то вроде AR по описанию, а говорят что вообще не ORM 6-/
                                                                      –1
                                                                      Нет, я не говорю, что не ORM, но правильно понимать, что это больше чем ORM.
                                                                    0
                                                                    xPDOObject — это же объект с методами set/get, save и т. п.?
                                                                      0
                                                                      Да.
                                                                        +2
                                                                        Классическая реализация ActiveRecord — класс абстрактной сущности, реализующей CRUD и наследуемые от него классы сущностей предметной области и приложения.
                                                                0
                                                                Индивидуальные акцессоры для полей $comment->setAuthor(new Author('VolCh'). Как вариант — публичные свойства $comment->author = new Author('VolCh')
                                                            +1
                                                            в нормальной ORM (Doctrine к примеру) генерация схемы идет из структуры ваших сущьностей. Тоесть вы описываете класс, а по нему уже генерятся методы.

                                                            Опять же если у вас уже есть таблица, одной командой можно сгенерить мэппинг класс. Геттеры/сеттеры умеют генерить почти все популярные IDE.

                                                            Это все же дело вкуса, но поддерживать код, использующий только PDO несколько сложнее.
                                                              0
                                                              В xPDO есть методы и генерации объектов из XML-схемы, и XML из описаний объектов, и объекты из структуры БД, и XML из структуры БД и т.п. Все что угодно.
                                                              При этом производные от xPDOObject объекты не требуют никаких методов вообще. Есть set(), get(), save(), remove() и этого достаточно. Есть и другие методы, но «этого достаточно».
                                                              На выходе мы получаем чистые заготовки, уже способные выполнять основные функции, и при желании можно их расширять как хочется.
                                                                +1
                                                                И что? Вот примеры с которыми Доктрина мне сильно упрощает жизнь:
                                                                — генерация миграций (diff структуры базы по сути производится)
                                                                — фильтры
                                                                — DQL (частенько бывает полезным)

                                                                Словом я вообще не понимаю о чем спор. Та же доктрина (как и большинство других ORM-ок) являются обертками над PDO и расширяют его функционал. Пользоваться или нет решать вам, но в своих проектах я всегда буду использовать ORM-мы, так как они сильно облегчают жизнь. Особенно если в один прекрасный день вы захотите перенести часть данных в MongoDB/PHPCR. Так, все что мне нужно будет сделать это изменить описание мэппинга. Логику же переделывать не придется по большей части.
                                                                  –1
                                                                  Вы наверно плохо проследили диалог. Я совершенно не против ORM и т.п. И вы можете работать со своим любимым инструментарием.
                                                                  Просто я попытался объяснить что такое xPDO, так как многие ошибочно думают, что его назначение — только взаимодействие с различными DB, что совершенно не так.
                                                                  И я не хотел кого-то убедить пользоваться именно им. Я просто показал его суть.
                                                                    0
                                                                    Вы показали, что xPDO — это ORM или почти ORM.
                                                                      0
                                                                      Это расширение ORM. То есть не только грузовик, но еще и груз имеет.
                                                                        0
                                                                        Не понял метафору.
                                                                          0
                                                                          К тому, что xPDO имеет функционал ORM, но имеет еще дополнительные функциональные объекты.
                                                                            0
                                                                            Как по мне ресолвинг пути файла или его URI/URL никак не должен касаться прослойки работы с базой. А если этот вопрос обойти, все тоже самое можно прикрутить к любой другой ORM, да и готовые реализации есть.

                                                                            Словом, считаю дальнейшую дискуссию не плодотворной, ибо вы просто описываете особенности MODx.
                                                                              0
                                                                              Взаимно.
                                  0
                                  А еще зачем-то придумали какие-то статические классы. Не понятно? Ну да и ладно. Каждому своё, и своё не каждому.
                                  0
                                  Ваш комментарий — отличная иллюстрация, подтверждающая обоснованность опасений, цитирую:

                                  однако многие ведущие разработчики опасались, что типажи будут использоваться не по назначению.
                                  0
                                  Любая организация логики на основе поведения. Когда добавление сущности в иерархию не дает ничего кроме проблем. Пример из моей практики, отчет по нескольким осям.
                                  Пример: есть репорты с группировкой по магазинам->покупателям->покупкам и по магазинам->продавцам->приобретениям. И это вроде бы укладывается в классическое наследование, но есть еще смешанные репорты, где есть и покупатели и продавцы, и вот тут классическое наследование идет боком.
                                  Пример 2: когда ты в рамках DDD пытаешься абстрагироваться от реализации слоя данных, который для разных репозитариев может быть схожим, а может раздичаться, может использовать разные источники хранения, а то и несколько и реализовывать логику объеденения данных.
                                    0
                                    Самый простой пример, лично мне, когда не хватало функционала — сделать из класса, у которого есть родитель, обсервер. Вроде и добавить надо 3 метода, но если надо парочку классов изменить?
                                      0
                                      Чтобы сделать наблюдателя, можно воспользоваться интерфейсами из SPL: SplObserver, SplSubject. И никакого наследования не надо.
                                        0
                                        Нужно методы этих интерфейсов реализовывать.
                                          0
                                          А в случае трейтов как? Ведь у каждого наблюдателя своя собственная реализация должна быть.
                                            0
                                            нет, не своя, все делается по интерфейсам, код общий у всех, просто евенты у каждого свои.
                                      0
                                      Вот такой пример. Предметная область — транспорт.
                                      class Transport {...}
                                      class RoadTransport extends Transport {...}
                                      class AirTransport extends Transport {...}

                                      А теперь нужно добавить подтип — пассажирский транспорт и грузовой. И пошли плодить подклассы:
                                      PassengerRoadTransport, CargoRoadTransport, PassengerAirTransport, CargoAirTransport.
                                      Либо наоборот — от транспорта наследовать грузовой/пассажирский, и от них уже наследоваться авто/жд/воздушный:

                                      А можно сделать трейты Cargo и Passenger, в которых реализовать специфичные реализации (виртуальных) методов.
                                      class Bus extends RoadTransport {
                                      use Passenger;

                                      }

                                      P.S. Если можно как-то оптимизировать структуру дерева классов без трейтов — подскажите, я что-то не соображу…
                                        0
                                        Паттерн Мост.
                                    +3
                                    Честно говоря, самое непонятное для меня нововведение в PHP начиная с PHP 3. Как работают разобрался, но вот на практике когда их нужно использовать, а когда нет, так и не понял. Как-то не возникает нужды в множественном наследовании.
                                      0
                                      Хороший пример использования типажей можно найти во фреймворке Silex. Там есть возможность подключать к приложению модули через них (для удобства).

                                      Сам я тоже еще не столкнулся с задачей где для реализации проекта нужно множественное наследования.
                                        0
                                        Я столкнулся в текущем проекте с трейтами. Точнее с трейтом и то он носит экспериментальный характер. Используется для подключения ServiceLocator к произвольному классу. Зачем такая странная реализация — без понятия.
                                          +3
                                          Ну как пример, если в Symfony проекте используется множество сервисов, в которые мы через контейнер хотим передавать ObjectManager, лично мне удобнее сделать трейт вида
                                          trait ObjectManager
                                          {
                                              protected $manager;
                                              public function setObjectManager (ObjectManager $manager)
                                              {
                                                  $this->manager = $manager;
                                              }
                                              protected function getObjectManager()
                                              {
                                                  return $this->manager;
                                              }
                                          }
                                          

                                          нежели передавать его через params конструктора.
                                          Ну это просто пример. Таким образом можно включать в классы часто дублируюмую функциональность.
                                            +2
                                            Когда я смотрю на ваш пример, мне приходит в голову еще один:
                                            Можно легко подключать возможность работы с кэшем для любого класса через трейты (методы getCacheKey, getCache, setCache)
                                              0
                                              Отличная мысль
                                              0
                                              Честно говоря не очень нравится подобная идея. К такому классу нужна инструкция: «после инстанцирования объекта не забудьте установить свойство такое-то».

                                              Надо поэкспериментировать с определением конструкторов в трэйте. Или, хотя бы, делать setObjectManager() protected/private и вызывать его в конструкторе класса, а в getObjectManager() проверять на null и бросать NPE для забывчивых. Хотя, конечно, от сценария использования класса зависит, но если (почти) всем методам класса менеджер нужен и его инициализация (почти) обязательна, то место этой инициализации в конструкторе.

                                                0
                                                Конструктор-то вы определить в трейте сможете (как __construct(), так и ClassName()).
                                                Но в этом случае вы:
                                                1. сможете сделать это только в одном трейте изо всех, используемых в классе и его предках.
                                                2. не сможете определить конструктор в самом классе.
                                                  +1
                                                  вот на счет второго утверждения вроде бы не совсем так. Вроде бы приоритет метода объявленного в классе выше чем в типаже. Но я лично не пробовал добавлять конструктор в типаж.
                                                    0
                                                    Верно, но в этом случае __construct() из трейта уже не будет конструктором класса и станет всего лишь рядовым методом.
                                                    0
                                                    1. insteadof… as… не поможет?
                                                    2. Обычные методы трэйтов я точно могу в «наследнике» переопределять, а с помощью insteadof as вызывать и методы «родители» из конкретного трэйта даже при конфликте имн в трейтах.
                                                      0
                                                      Все верно говорите, с помощью такого способа можно генерировать прокси-трейты. Правда количество методов в конечном классе будет расти из-за добавления альясов в трейте.
                                                        0
                                                        Вот чем меня трэйты и смущают — на сферовакуумных примерах вроде тема интересная, а как пытаешься что-то реализовать, то написать вроде не проблема, но очень трудночитаемый код получается, по-моему. Или просто синдром «коряка не читатель — коряка писатель!»
                                                        0
                                                        Видимо я недостаточно ясно выразился.

                                                        Конструктор в классе, использующем трейт, молча заместит конструктор из трейта. Конфликт имён конструкторов, определённых в трейтах придётся разрешать явно, через insteadof/as.

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

                                                        То, что метод, определённый в трейте, может вообще в принципе выполнять роль конструктора класса для меня выглядит несколько странным.
                                                          0
                                                          Вот я хотел поэкспементировать насчёт того получится или нет. То есть через инстид определяем алиасы для конструкторов из трейтов, а в конструкторе класса эти алиасы вызываем.
                                                            0
                                                            Получится, но никаких преимуществ от того, что методы будут называться __construct() не будет:

                                                            file.php
                                                            <?php
                                                            
                                                              trait Foo {
                                                            
                                                                function __construct() { echo "Foo::__construct()\n"; }
                                                            
                                                              }
                                                            
                                                              trait Bar {
                                                            
                                                                function __construct() { echo "Bar::__construct()\n"; }
                                                            
                                                              }
                                                            
                                                              class FooBarClass {
                                                            
                                                                use Foo, Bar {
                                                                  Foo::__construct as initFoo;
                                                                  Bar::__construct as initBar;
                                                                }
                                                            
                                                                public function __construct() {
                                                                  echo "FooBarClass::__construct() {\n";
                                                                  $this->initFoo();
                                                                  $this->initBar();
                                                                  echo "}\n";
                                                                }
                                                            
                                                              }
                                                            
                                                              $objFooBar = new FooBarClass();
                                                            
                                                            ?>
                                                            
                                                            

                                                            output
                                                            X:\>php.exe file.php
                                                            FooBarClass::__construct() {
                                                            Foo::__construct()
                                                            Bar::__construct()
                                                            }


                                                            С тем же успехом мы могли их изначально назвать initFoo() и initBar().
                                                      0
                                                      Если это применять к сеттерам, то DI умеет после инициализации сэтить значения. Это зачастую очень удобно. Так что трейты тут очень даже подходят.
                                                        0
                                                        Да, именно это я и имел в виду, а в описании сервиса делать
                                                        services:
                                                            MyService:
                                                                class: NS\MyBundle\Service\MyService
                                                                calls:
                                                                  - [ setObjectManager,   [ @doctrine.orm.entity_manager ] ]
                                                        
                                                        0
                                                        Не надо никакой инструкции. В случае Symfony 2, просто прописывает зависимость:
                                                        services:
                                                            MyService:
                                                                class: NS\MyBundle\Service\MyService
                                                                calls:
                                                                  - [ setObjectManager,   [ @doctrine.orm.entity_manager ] ]
                                                        
                                                      +1
                                                      Мы у себя трейты исполуем во всяких DTO и еще примерно так gist.github.com/1034079

                                                      Хочу добавить, что трейты — это не про наследование. Это про горизонтальное расширение.
                                                        0
                                                        По второмц пример. Я правильно понял, что вы из DataMapper делаете ActiveRecord?
                                                          0
                                                          не, я бы так делать не стал, но SerializableEntity, Timestampable вполне себе =)
                                                            +2
                                                            Вот это, да, нормальная идея. Дальнейшее развитие интерфейов типа *able. Довольно часто в *able классах приходится писать реализации таких интерфейсов мало чем отличающиеся друг от друга. Правда, нужно будет организовывать какие-то колбэки, которые обязательно должны бы в типажируемом классе или использовать рефлексию, ведь типаж ничего о классе не знает. В общем к типажу нужна инструкция по использованию, соглашения, которым должен отвечать типажируемый класс.
                                                      0
                                                      Phython'ом мой любимый язык ещё никто не обзывал…
                                                        +3
                                                        так было в оригинале, я решил сохранить стилистику)
                                                        +4
                                                        Согласен с распространённым мнением, что это теоретически не столько множественное наследование, сколько умный копипаст.
                                                        Другое дело, что на практике в значительном количестве случаев множественное наследование используют именно для копипаста.
                                                          0
                                                          Лучше бы декораторы сделали…
                                                            0
                                                            Поддерживаю. Очень хотел бы видеть в PHP декораторы похожие на те которые есть в питоне
                                                              0
                                                              У меня есть реализция PHP декоратора — можешь глянуть в профайле ссылку на статью.
                                                                +3
                                                                В Вашей реализации есть достаточно заметные недостатки, а именно необходимость изменять исходный код декорируемых классов (use TDecorator;).
                                                                Такая реализация бесполезна в случае использования сторонних библиотек.

                                                                Советую всеже посмотреть как декораторы реализуются в питоне — там это сделано очень красиво за счет метапрограммирования и переопределения функций/методов в рантайме. Именно о такой реализации я и мечтаю.
                                                                  –1
                                                                  Тоже самое будет и в Python: невозможно без изменения кода сторонней библиотеки декорировать метод класса.
                                                                    +2
                                                                    Совсем не тоже самое.
                                                                    Допустим у нас есть декоратор:
                                                                    def decorate(func):
                                                                    	def world(*args, **kwargs):
                                                                    		func(*args, **kwargs)
                                                                    		print "World"
                                                                    	return world
                                                                    


                                                                    Тут возможны 2 случая:
                                                                    1) Вы хотите добавить этот функционал в код всех обьектов некого класса
                                                                    class Decorated:
                                                                    	@decorate
                                                                    	def speak(self):
                                                                    		print "Hello"
                                                                    

                                                                    теперь все вызовы метода будут проходить через декоратор

                                                                    2) Добавить функционал к одному из обьектов данного класса

                                                                    test = Decorated()
                                                                    test.speak = decorate(test.speak)
                                                                    test.speak()
                                                                    

                                                                    И в этом случае вам не надо изменять код самого класса.
                                                                      0
                                                                      То есть в Вашем понимании вот это:
                                                                      class Decorated:
                                                                          @decorate
                                                                          def speak(self):
                                                                              print "Hello"
                                                                      

                                                                      не изменить исходный код класса?
                                                                        0
                                                                        Я специально привел 2 варианта: с изменением и без. Во 2-м варианте исходный код класса не изменяется:
                                                                        class Decorated:
                                                                            def speak(self):
                                                                                print "Hello"
                                                                        
                                                                        test = Decorated()
                                                                        test.speak = decorate(test.speak)
                                                                        test.speak()
                                                                        

                                                                        Прошу прощения если в первый раз привел недостаточно подробный пример
                                                                    0
                                                                    Метапрограммирование и переопределение методов в рантайме уже есть ) Без экстеншенов, без магии, с очень низким оверхедом на вызов перехваченого метода. Библиотека Go! AOP к вашим услугам. Только ей под силу добавить к любому вашему классу нужный трейт, не меняя исходный код оригинальных классов.
                                                                    Пример: берем некоторый класс Example (в нем нет трейтов и интерфейсов), дальше нам захотелось иметь возможность сериализовать объекты данного класса, не меняя исходный код класса. Все просто — создаем трейт SerializableImpl и объявляем совет DeclareParents с интерфейсом Serializable и трейтом SerializableImpl в отношении класса Example, после чего наш класс Example будет имплементировать интерфейс Serializable, в чем можно убедиться проверкой instanceof.
                                                              +1
                                                              Лучше бы нативную поддержку юникода сделали…
                                                                0
                                                                Так вроде с 5.4 она есть?
                                                                  0
                                                                  Нет, всё примерно так же как и раньше — mb_* функциями. А нативную поддержку обещали в 6.0, который неизвестно когда выйдет. тоже очень жду.
                                                                    0
                                                                    Нда, посмотрел php.net/manual/en/language.types.string.php#language.types.string.details — какой-то бардак и анархия сейчас :(
                                                                      0
                                                                      Угу, и это в 2013 году в языке, который HyperText Preprocessor. В Java полная поддержка unicode была уже в 1998 году.
                                                                        0
                                                                        Сдается мне, в том то и проблема, что изначально на юникод не ориентировались, и сейчас приходится переписывать тонны кода и ничего при этом не сломать.
                                                                          +1
                                                                          Ну Python, Ruby как-то смогли. Начинали с того же примерно, что и в PHP в этом плане.
                                                                            0
                                                                            В каком месте в питоне смогли? Python 3 не используется как раз из-за несовместимости.
                                                                              0
                                                                              Python 3 не используется

                                                                              Спорное утверждение.
                                                                              python3wos.appspot.com/
                                                                              Процесс идет, медленно но верно.
                                                                                0
                                                                                Python 3 вышел 4 года назад. Django до сих пор его не поддерживает.
                                                                                Я не считаю данное утверждение спорным, особенно учитывая, что примерно половина библиотек по вашей же ссылке его не поддерживают.
                                                                                0
                                                                                А при чем тут Python 3? Даже во втором поддержка юникода на все еще недостижимом для php уровне.
                                                                        +5
                                                                        6.0 не будет. Юникод не получился. До скончания веков mb_ вызывать.
                                                                          +1
                                                                          Решение не из лучших, но можно юзать mbstring.func_overload.
                                                                            +2
                                                                            Это очень плохое решение, никогда так не делайте. Огромное количество php-библиотек предполагает, что строковые функции оперируют байтами (например, strlen често используется для получения именно размера (двоичной) строки в байтах). Оверлоад эти библиотеки ломает, причём в самых неожиданных местах.
                                                                              0
                                                                              Спасибо, хорошо. Я всегда догадывался, что это еще тот костыль, и сам никогда его не использовал.
                                                                                0
                                                                                вот ни разу не попадались подобные библиотеки. Я так понимаю это относится к случаям, когда нужно что-то в поток отправить (аля структуру какую-то), но не уверен. Можете привести пример?
                                                                                  0
                                                                                  а вот я столкнулся с проблемой кодировок тут
                                                                                  sphinxsearch.com/forum/view.html?id=1136
                                                                                  sphinxsearch.com/forum/view.html?id=530
                                                                                  This is interesting enough so I'll make a translation for those who do not speak Russian
                                                                                  as well.

                                                                                  David points out that mbstring.func_overload, which enables standard PHP string functions
                                                                                  to work OK with UTF-8, might be causing troubles with sphinxapi.php which uses strlen()
                                                                                  when forming request.

                                                                                  He also suggests a fix to sphinxapi.php which would check that and temporarily switch the
                                                                                  encoding to latin1. (which I suppose fixes strlen())
                                                                                    +1
                                                                                    Ну да, я и есть тот Давид:) Ещё я с этим сталкивался в PHPExcel, PHP Markdown, PHPMailer… в общем, сто раз уже пожалел, что принял когда-то решение использовать оверлоад в проекте. Приучить себя писать везде mb_* гораздо проще, чем разруливать такие вот глюки.
                                                                          +1
                                                                          Не сделают, т.к. старый код перестанет работать.
                                                                          Хотя я за полное перепроектирование всей стандартной библиотеки, но чтобы старые функции все равно были доступны.
                                                                            0
                                                                            Полное перепроектирование слишком много времени займет. Да и я не припомню, когда у меня в последний раз на проектах были проблемы с обработкой юникода. Я больше жду, когда парсер PHP файлов перепишут, что бы на выходе он генерил не опкоды сразу, а сначала AST.
                                                                          0
                                                                          Еще из интересных применений трейтов — динамическое их подключение к конечным классам с помощью аспектно-ориентированного программирования. Я как раз недавно сделал поддержку технологии внедрения (Introduction) трейтов в любой класс, а также добавил уникальную возможность перехвата методов в трейтах с помощью генерации прокси-трейтов.

                                                                          Так что трейты — это хорошо, в сочетании с интерфейсами. А декораторы уже есть благодаря АОП.
                                                                            0
                                                                            А в чем смысл? Ну тоесть, я не могу представить ситуации, когда может понадобится возможность динамически менять классы приложения. Использовать как плагины? Вместо декораторов? Да и меня немного смущает факт того, что в последнее время все больше и больше людей пытаются решить какие-то проблемы при помощи АОП. Может быть для сервисных задачь оно и подходит (профилирование кода, логирование), но все же я против этого подхода. Хотя это опять же лично мое мнение.
                                                                              0
                                                                              Я уже в своей статье на хабре приводил пример АОП, когда достаточно перед методом добавить аннотацию @Cacheable — и он будет кэшироваться, неважно какой метод — динамический, статический, или же вообще в трейте. Это пример номер раз.
                                                                              Пример номер два (про него еще будет отдельная статья на хабре): есть у вас тонна сущностей доктрины, а вам хочется отдавать их как-то красиво в JSON и начинается вызов тучи геттеров, либо гидрация, а можно сделать это очень элегантно — ко всем классам-сущностям добавить интерфейс JsonSerializable и трейт с реализацией этого интерфейса. Профит. После этого можно любую сущность заворачивать в REST-интерфейс одним контроллером.
                                                                              Из реальных примеров — для админки SonataBundle одним классом добавляем журналирование всех действий в админке. Неплохо, да, не меняя оригинальный код?
                                                                                0
                                                                                В одном из проектов так же реализовывал кеширование сабреквестов для отображения виджетов. Но там все же не AOP а события. Тоесть у вас есть событие onRequest где мы проверям закешили мы уже или нет? Если закэшили то просто отдаем ответ из кэша. И событие onResponse, где мы забираем ответ и смотрим, нужно ли его кешировать.
                                                                                  0
                                                                                  Использование событий влечет за собой написание шаблонного кода, поэтому вы не сможете расширить логику любого метода, если он заранее не написан с учетом возможного расширения. Да и обработка событий добавляет очень большой оверхед. Так что у меня в библиотеке нет никаких событий, хотя если сравнивать по смыслу — то да, в какой-то мере это событие. Только можно создать его в любом месте кода без предварительной подготовки )
                                                                            0
                                                                            I also fear that it may fall into the category of often-abused-features such as eval(), goto, constants, the @ operator, class inheritance and regular expressions.


                                                                            Как можно злоупотреблять константами?
                                                                              0
                                                                              При разработке нового проекта возникла необходимость множественного наследования, ну или множественного использования части кода, я очень рад что на этот момент примеси ( трейты) уже были реализованны.
                                                                              Вот пример: Описывая модели, я столкнулся с тем, что ряд моделей имеют общий код, но в радителя его вставить нет возможности, объясню почему. Модели описывались визуальных объектов, с дальнейшим общением с JavaScript. Была описанна базовая модель Компонент, в котовую вынесена вся общая часть визуальных компонентов (координаты, размеры, ...). Далее описывались сами компаненты, для которых был создан ряд общих родителей (общий для кнопок, у которых было событие нажатия, общий для компонентов, которые могут иметь дочерние элементы, ...) Проблымы появились тогда, когда я добрался до компонентов Изображение и ИзображениеКнопка. По сути ИзображениеКнопка дочерняя сущность от сущности Кнопка, т.к. есть обработчик нажатия, но в ней есть еще описание и весь функционально компонента Изображение, т.к. полностью повторяет функционально и Кнопки и Изображения! Тут я и воспользовался возможностями примесей. Скажу Вам что пхпШторм очень хорошо умеет с ними работать и я еще не пожалел что воспользовался ими. Для большей убедительности, стоит сказать что подобных компонентов у меня несколько, которые содержат полное или частичное дублирование.

                                                                              Пишу с телефона, прошу прощения за ошибки и опечатки.
                                                                                0
                                                                                Проблымы появились тогда, когда я добрался до компонентов Изображение и ИзображениеКнопка. По сути ИзображениеКнопка дочерняя сущность от сущности Кнопка, т.к. есть обработчик нажатия, но в ней есть еще описание и весь функционально компонента Изображение, т.к. полностью повторяет функционально и Кнопки и Изображения! Тут я и воспользовался возможностями примесей.
                                                                                IMHO композиция кнопки и изображения выглядело бы здесь более логичным решением.
                                                                                +1
                                                                                Действительно, несколько странно, что типажи получают возможность иметь состояние, что довольно не верно по идеологии паттерна. То есть, получается, что это что-то соеднее между примесями (mixins) и собственно трейтами.

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

                                                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                Самое читаемое