Pull to refresh

Aleph PHP Framework

Reading time 6 min
Views 5K

Итак, встречайте Aleph!


Новый микро-фрэймворк на PHP, по размеру и функционалу, которого уместно сравнение разве что только с медицинским скальпелем.

По умолчанию содержит всё необходимое для быстрого старта и написания приложений.

Причины, почему стоит обратить на него внимание:
  • Фрэймворк реально маленький. Обильно сдобренный phpDoc комментариями код занимает около 3000 строк;
  • Фреймворк является результатом более чем 6-ти летней профессиональной деятельности его авторов в области web-разработок;
  • Возможности фрэймворка позволяют использовать его как базу под практически любое приложение.

Причём Aleph — это пока что только ядро полноценного фреймворка, уже готового и давно используемого в реальных web-приложениях. Публикация остальных частей системы не за горами — вы просто влюбитесь в возможность проектировать и реализовывать приложения так, как если бы вы делали это в десктопном программировании (не надо пытаться представить это прям сейчас и тут же критиковать, дождитесь пока не увидите это своими глазами, и поймёте, что я имел в виду). Есть и ORM, и система контролов (именно контролов, типа тех, что в ASP.Net), валидаторы, кэширование, шаблонизация и всё то, что делает набор вспомогательных библиотек фреймворком.

Ядро написано на php 5.3.0 и код использует возможности языка, появившиеся в этой версии. Код распространяется по лицензии MIT, ссылки на гитхаб и сайт с документацией и форумом — в конце статьи кода немного, всё прокомментировано, пояснения по структуре есть на сайте.

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

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



В корне проекта видим следующее — файл index.php, что является единой точкой входа в приложение (уверен, не мне вам рассказывать о содержимом лежащего рядом .htaccess), папка lib, в которой лежит собственно само ядро (файл aleph.php) и специальный скрипт requirements.php, результаты запуска которого подскажут вам, готова ли ваша система для запуска приложений на базе Aleph. В корне также лежит файл 404.html в качестве примера шаблона страницы ошибки.



Но самое интересное для нас, конечно же, содержимое папки app. Без лишних деталей: папка cache — для хранения специальных файлов кэша при выборе в конфигурации кэширования на файлах (идёт вместе с ядром), и папка logs для служебных файлов логирования системной информации. Никаких жёстких ограничений (как и вообще ограничений во фреймворке) на расположение и название этих папок не накладывается (всё это запросто конфигурируется).

В папке engine лежат уже непосредственно файлы нашего приложения.

В качестве демонстрации был выбран не магазин, не блог и даже не todolist. Потому что когда смотришь реализацию блога на %framework_name% или реализацию магазина на %another_framework_name% невольно начинаешь задумываться «это хорошо, в рамках поставленной задачи фреймворк ведёт себя отлично, но как на нём сделать то, что мне нужно?». Aleph не отвечает на эти вопросы, он даёт вам отличный инструмент для адаптации к тому, что вам нужно. Помните, про парня, которому нужен был молоток? (Из статьи http://habrahabr.ru/post/141477/). Так вот, в php всё ещё пользуются молотками, и это имеет практический смысл, если вы понимаете, о чём я.

Впервую очередь продемонстрируем возможности роутинга в ядре. Все мы прекрасно знаем, что регулярные выражения в умелых руках — классная штука, этим роутинг и пользуется. Взглянем на содержимое файла index.php:

<?php

// на случай выполнения скрипта в шелле
$_SERVER['DOCUMENT_ROOT'] = __DIR__;

// единственный инклуд для файла ядра
require_once('lib/aleph.php');      

// инициализация ядра файлом конфигурации
$a = Aleph\Core\Aleph::init()->config('app/engine/config.ini');

// удаляем из файлового кэша "просроченные" данные
if (method_exists($a->cache(), 'gc') && isset($a['cache']['gcProbability']))
{
  if ((int)$a['cache']['gcProbability'] > rand(0, 99)) $a->cache()->gc();
}

// непосредственно роутинг
$map = array('/#method|add|sub|div|mul#/#a|[+\-]?[0-9]*\.?[0-9]+([eE][+\-]?[0-9]+|)#/#b|[+\-]?[0-9]*\.?[0-9]+([eE][+\-]?[0-9]+|)#' => 'Aleph\Demo\Arithmetic->route', 
             '/rom2dec/#x|(?i)M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])#' => 'Aleph\Demo\Transform->rom2dec', 
             '/dec2rom/#x|[1-9]{1}[0-9]{0,6}#' => 'Aleph\Demo\Transform->dec2rom', 
             '/#method|akkerman|gcd#/#a|[0-9]+#/#b|[0-9]+#' => 'Aleph\Demo\Misc->route',
             '/sets/#vars|[0-9a-zA-Z\/]+#' => 'Aleph\Demo\Misc->sets');

// привязываем к маршрутам автоматические действия
foreach ($map as $url => $act) $a->bind($url, $act);

// выполняем поиск действия для получения результата
$result = $a->route();

// отдаём ответ на основе результата
if ($result !== null) 
{
  $a->response()->stop(200, $result);
}
else 
{
  $a->response()->stop(404, file_get_contents('404.html'));
}

Карта маршрутов — массив, ключами которого являются регулярные выражения, соответствующие запросу, причём ключи могут содержать переменные (#method|...#, #a|...#) которые потом будут использованы как именованные параметры, а значениями — соответствующие методы необходимых классов.

Примеры валидных вызовов, согласно маршрутам:
http://demo.4leph.com/rom2dec/MMDCXCVIII (перевод из римской в десятичную)
http://demo.4leph.com/dec2rom/2012 (перевод из десятичной в римскую)
http://demo.4leph.com/sets/hab/ra/habr (генерация вариантов множеств из указаных данных)
http://demo.4leph.com/akkerman/3/3 (вычисление функции Аккермана, значения параметров ограничены максимальными 3 и 3, цель метода — показать работу с кэшированием результатов вместо постоянного вычисления)
http://demo.4leph.com/add/1243.454e+45/-2.45 (вычисление нехитрым калькулятором)

Естественно вместо этих, представленных намеренно, академических примеров могли бы быть, набивших оскомину, /product/1532/details/a-title-of-product, и даже более того, можно без проблем реализовать разную выдачу по запросам /product/1532/details/a-title-of-product, /product/1532/details/a-title-of-product.xml, /product/1532/details/a-title-of-product.json и в том же духе. Всё это очень просто реализуется, как вы уже могли заметить.

Остановимся подробнее на выполнении
$result = $a->route();

При запросе вида demo.4leph.com/add/1243.454e+45/-2.45 будет вызван метод Aleph\Demo\Arithmetic->route с параметрами 'add', '1243.454e+45' и '-2.45' Смотрим же реализацию метода (файл app/engine/arithmetic.php):

<?php

namespace Aleph\Demo;

class Arithmetic extends Calculator
{
  public function add($a, $b)
  {
    return $a + $b;
  }
 
  public function sub($a, $b)
  {
    return $a - $b;
  }
  
  public function mul($a, $b)
  {
    return $a * $b;
  }
  
  public function div($a, $b)
  {
    if ($b == 0) return 'Error: the second argument cannot be zero.';
    return $a / $b;
  }
}

Класс Arithmetic в свою очередь наследуется от класса Calculator, который реализует метод route:

<?php

namespace Aleph\Demo;

class Calculator
{
  public function route($method, $a, $b)
  {
    if (method_exists($this, $method)) 
    {
      return call_user_func_array(array($this, $method), array($a, $b));
    }
    return 'Error: method "' . $method . '" doesn\'t exist in class "' . get_class($this) . '"';
  }
}

Кажется, тут всё очевидно и не должно вызывать вопросов.

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

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

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

Больше информации о содержимом ядра на официальном сайте, в разделах Справочник Классов и Документация.

Вместо заключения


Хочется ещё раз заметить, что опубликованная часть это пока что только ядро. Не стоит бросаться в сравнения и спрашивать чем это лучше известных решений, требовать тестов производительности и прочее. На подходе к публикации и ORM и Page Object Model и всё остальное. Когда на рынке php полно решений сделанными одними профессионалами для других, очень не хватает решения, сделанного профессионалами для непрофессионалов чтобы сделать их работу более профессиональной.

Официальный сайт
Репозиторий на GitHub
Демо пример
Пустой пока форум, ожидающий первых посетителей
Tags:
Hubs:
0
Comments 58
Comments Comments 58

Articles