Пользователь
0,0
рейтинг
12 июля 2014 в 18:37

Разработка → ZExt PHP Framework из песочницы

Данным постом хочу представить IT-сообществу свой давний проект: PHP фреймворк «ZExt».

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

Фреймворк представляется «как есть» и его автор не несёт ответственности за его использование.
Репозиторий на GitHub.

Фреймворк требует PHP версии не ниже 5.4.
Для работы компонентов требуется добавить пространство имён «ZExt» в автозагрузку классов (PSR-0) по пути: «my_app_library/ZExt».

Можно воспользоваться собственным автозагрузчиком классов фреймворка:
require 'my_app_library/ZExt/Loader/Autoloader.php';

ZExt\Loader\Autoloader::registerDefaults();


Так же можно добавить фреймворк через Composer:
{
	"require": {
		"zext/zext": "dev-master"
	}
}


Возможности


Фреймворк предоставляет средства работы с базами данных: ORM для работы с MongoDB, надстройка над Phalcon ORM.
Кеширование данных с поддержкой тегов.
Конфигурация приложения.
Средства работы с зависимостями компонентов приложения (Dependency Injection).
Средства отладки и профилирования приложения.
Форматирование чисел, дат.
Подстветка кода.
Помощники построения HTML-кода и вывода информации в консоль.
Средства интернационализаци.
Средства страничной навигации.
Автозагрузчик классов.
Ряд архитектурных компонентов: система мапперов, моделей и коллекций, валидация в моделях, ряд трейтов упрощающих работу с зависимостями, кешированием, логгированием, помощниками и т.д.

Теперь немного о его компонентах:

Debug


Компонент представляющий набор средств для отладки PHP-приложений.
Может использоваться в любом приложении вне зависимости от используемых в нём фреймворков и прочих технологий.
Использует jQuery подключенный в вашем проекте или, при его отсутствии, подключает сам через GoogleApis.

Подключение отладочной панели с параметрами по умолчанию:
$debug = ZExt\Debug\DebugBar::initDefaults();

Вывод информации производится в нужном месте (на пример в скрипте вида (view)) через приведение объекта отладчика к строке:
echo $debug;

Результатом работы отладчика будет вот такая панель:


Попробуем бросить исключение:
throw new Exception('Looks like an error occurred...', 100);

При этом отладчик, перехватив его, вернёт отладочную информацию в качестве ответа на запрос:

Слева появился элемент «Exception» с информацией о брошенном исключении.

Совершим не фатальные ошибки:
echo $undefinedVar;

trigger_error('something wrong');



Profiler


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

Сымитируем обращение к некому сервису приложения и добавим профилировщик в панель отладки:
$profiler = new ZExt\Profiler\Profiler();

$profiler->startRead('Database read');
sleep(1); // Read from some service
$profiler->stopSuccess();

$profiler->startWrite('Database write');
sleep(1); // Write to some service
$profiler->stopError();

$profiler->setName('Database')
         ->setIcon('db');

$debug->addProfiler($profiler);

Теперь посмотрим результаты:


Html


Компонент призван облегчить создание различных HTML-конструкций.

Возмём тег с большим количеством атрибутов:
$tag = new ZExt\Html\Tag('iframe');

$tag->width       = 640;
$tag->height      = 480;
$tag->frameborder = 0;
$tag->scrolling   = 'no';
$tag->src         = 'page.php';
$tag->id          = 'frame';

echo $tag;

<iframe width="640" height="480" frameborder="0" scrolling="no" src="page.php" id="frame"></iframe>

Список:
$list = new ZExt\Html\ListUnordered();

$list->id    = 'list';
$list->title = 'My list';

$list[] = 'Item 1';
$list[] = 'Item 2';
$list[] = 'Item 3';
$list[] = 'Item 4';

echo $list;

<ul id="list" title="My list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>


Планы развития


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

Если сообществу будет интересен представленный проект, я буду продолжать публиковать гайды по работе с компонентами фреймворка и архитектурными решениями в которых фреймворк участвовал.
Михаил @mike66
карма
8,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (24)

  • +4
    Насколько я понял по описанию — фреймворк предоставляет средства отладки и хелперы html. =)

    Предлагаю хотя бы кратко описать возможности, т.к. репозиторий не маленький и работы судя по всему было проделано много: github.com/mikemirten/ZExt/tree/master/library/ZExt
    • 0
      Вы правы. Добавил краткое описание возможностей.
      В будущем планирую подробно осветить возможности компонентов и их использование.
  • +5
    Может кто объяснить, в чем профит конструирования HTML через объекты? Это же медленно и неудобно. Скажем тот же пример с iframe или списками. Никакой критики, просто любопытство.
    • 0
      Ну это абстракция. При конструировании, допустим форм — можно аттачить на лету данные из моделей, как реализовано в Laravel, автоматом добавляется csrf токен и прочие мелочи.
      • 0
        Вы предлагаете верстальщикам писать код, а не делать верстку?
        • –1
          Это всё таки инструмент программиста, а не верстальщика. Он может быть использован на пример в каком либо декораторе, абстрагируя логику от представления.
          • +1
            Может быть пример просто слишком простой, но даже по API это констркутор HTML. Да, можно добавлять свои штуки туда, инджектить дополнительное поведение — но это можно делать и с шаблонами и не извращаться до такой степени.
        • 0
          Я предлагю верстальщикам использовать то, что им будет удобнее в том или ином случае.
      • 0
        С формами все понятно и все ясно. Но там так же HTML выносится в шаблоны, абстракции обычно над типами инпутов и основная цель таких абстракций — биндинг данных модели на формы и обратно. А то что у вас — это ИМХО избыточная абстракция, PHP ради PHP.
        • 0
          Ну, допустим, не у меня ( у автора) и мне подход выкидывания всего в php не нравится, но постараться оправдать (или предположить) могу — просто обычный принцип разделения кода (что бы не смешивать html и php — раз в 100 лет такое бывает надо), доведённый до абсурда =)
        • 0
          Я понимаю вашу точку зрения и во многом согласен с ней.

          Но иногда, на пример, возникает дилема: создать шаблон ради вывода одного тега, передав в него значения атрибутов, или описать всё в хэлпере или декораторе. Количества кода в последнем будет практически одинаковым, так же будет абстракция от представления, а вот создание шаблона ради вывода одного тега действительно может попасть под определение «PHP ради PHP».

          Всё зависит от ситуации. Я лишь предложил один из вариантов решения.
    • +1
      Иногда возникает потребность собрать некоторые HTML-конструкции с большим количеством аттрибутов, часть из которых добавляется по различным условиям, значения которых могут подставлятся из моделей и прочих провайдеров данных. Получается нечто находящееся на стыке бизнес-логики и представления. Если разместить это в скрипте представления, он будет перегружен конструкциями вида "<?php if (condition): ?>", "<?= $model->property ?>" внутри тэга. Если разместить в контроллере или хэлпере, получится каша из конкатенций частей HTML-кода.

      Для примера:
      $tag = '<div attr1="value"';
      
      if ($needAttr2) {
          $tag .= ' attr2="' . $attr2Value . '"';
      }
      
      $classes = [];
      
      if ($active) {
          $classes[] = 'active';
      }
      
      if ($warning) {
          $classes[] = 'warning';
      }
      
      if (! empty($classes)) {
          $tag .= ' class="' . implode(' ', $classes) . '"';
      }
      
      $tag .= '></div>';
      


      Против:
      $tag = new Tag('div');
      
      $tag->attr1 = 'value';
      
      if ($needAttr2) {
          $tag->attr2 = $attr2Value;
      }
      
      if ($active) {
          $tag->addClass('active');
      }
      
      if ($warning) {
          $tag->addClass('warning');
      }
      
      • +2
        Вы бы сделали Fluent интерфейс для тегов. Было бы здорово:

        $tag->attr1('value')->attr2($needAttr2, 'value')->addClass('class3');
        

        • 0
          Уже реализованн в следующем виде:

          $tag = new Tag('p');
          
          $tag->setAttr('data-pk', 123)
              ->setAttr('data-name', 'John')
              ->addClass('has-comments');
          


          На счёт варианта с именами аттрибутов в качестве имён методов подумаю.
          Спасибо за идею.
      • 0
        А если третий вариант?

        <div data-attr1="value" 
                 {% if needAttr2 %} data-attr2="value" {% endif %} 
                 class="{{ className({active: active, warning: warning})  }}">
        </div>
        


        // экстеншен-хелпер
        // ключь - имя нашего класса, значение - условие, когда его нужно отображать
        function className(array $classes = array()) {
            return array_keys(array_filter($classes, function ($enabled) {
                return $enabled;
            }));
        
        }
        
        • 0
          Вообще лично я не так уж частно сталкивался с подобным (кучи условий и прочее) и обычно я решал эту проблему за счет выноса всего этого в макрос, или нечто подобное (в зависимости от проекта). Таких ситуаций у меня было… ну несколько, и чаще всего это были формы. Так вот, если брать тот же Twig, за счет наследования шаблонов, возможность импорта различных макросов, гибкости в плане расширения синтаксиса — все эти архаичные классы типа CHtml/Tag и прочее не нужны. Да они и раньше не особо то нужны были.
        • 0
          Вариант конечно имеет право на жизнь, но вы не находите, что в сумме это более сложная конструкция и менее «читабельная»?
          • 0
            эта конструкция намного проще вашей (что вариант с конкатенацией, что вариант с конструктором), метод хэлпер реализуется один раз, покрывается тестами и уходит на покой и больше не мельтишит. А количество кода на тэг существенно уменьшается, что должно давать профит при поддержке. По сути ваш вариант помогает избежать ошибок конкатенации, это единственный вариант при котором я вижу существенный профит. Но если избавиться от канкатенации на корню, проблемы такой и не будет вовсе.

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

              Где и как будет распологаться логика определяющая появления классов в конструкции ниже?
              {{ className({active: active, warning: warning}) }}

              Аттрибут «class» будет висеть всё время, даже пустой?
              Я конечно понимаю, что он ничего не испортит, но по моему это не есть хорошая практика.

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

              Нет уж, извините, но я в этом не вижу более простого решения.

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

              Ок. Давайте сойдёмся на том, что у нас с вами разный взгляд на решение одного и того же вопроса и оба решения имеют право на жизнь.
  • –2
    Отличный фреймворк, уже год с ним работаю, действительно облегчает жизнь php программиста ))
    • 0
      Это мое ИМХО, я действительно пользуюсь этим фреймворком и я написал об этом.
      Фреймворк обкатан на продакшене, под нагрузками, mysql + memcache + mongo, проект крутится на нескольких серверах, настроена репликация, лоад балансеры, работаем в моного с коллекциями по 500Гб.
      Так же, в этом фреймворке, есть хороший удобный профилер, который очень облегчает жизнь в бою.
      Лучше бы вопросы по работе либы задавали и чего в документации не хватает.
      Не хотите разбираться? Не хотите доку читать? Так не кто ж не навязывает, — просто пройдите мимо ))
  • 0
    1) Какого рода проекты делаются на этом фреймворке: хайлоад, сайты со сложной бизнес-логикой, обычные сайтики?
    2) Что с шаблонизатором?
    3) Опубликуйте на packagist что ли. А то так несерьезно.
    4) Зачем свой автозагрузчик, если есть в Composer?
    5) composer.json гол как сокол. Неужели все компоненты сами честно свелосипедили? Зачем?
    • 0
      1) Основной проект указан в тексте поста. В двух словах: относительно хайлоад со сложной бизнес-логикой.

      2) Использовался шаблонизатор стороннего фреймворка, в частности: Phalcon. В посте описанно, что фреймворк изначально был не более чем библиотекой расширяющей возможности некоторых фреймворков.

      3) Согласен. Это в ближайших планах.

      4) На пример, что бы дать возможность использовать фреймворк в проекте без композера. Были и другие причины.

      5.1) Чего конкретно вам не хватает в composer.json?
      5.2) Что именно вас удивляет? Что можно вот так взять и самому, честно писать код? )
      5.3) Это была моя работа, за это платили деньги. Кроме того я люблю своё дело.
  • +1
    >> 4) На пример, что бы дать возможность использовать фреймворк в проекте без композера

    По мне, так всех надо насильно пересаживать на composer. Всем лучше будет, если он будет стандартом веб-разработки.

    >> 5.1) Чего конкретно вам не хватает в composer.json?

    Есть посмотреть даже такого монстра как Laravel, то там огромный список внешних зависимостей. А у вас прямо совсем все свое))

    >> 5.1 5.2 5.3

    Я понимаю, когда пишут свой IoC.
    Я очень понимаю, когда пишут свою реализацию MVC, Requesting, Routing.
    Но честно, никогда не понимал, зачем пишут свои Cache, Session, Validator и прочее, не говоря уже об ORM или шаблонизаторе. Чем ваша реализация Cache, Session, Validator принципиально отличается от тонны подобных либ на гитхабе? Не проще было взять готовые решения? Тем более выбор-то достойный.

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