zer0-framework / core
Installs: 2 193
Dependents: 24
Suggesters: 0
Security: 0
Stars: 4
Watchers: 2
Forks: 1
Open Issues: 0
Type:framework
Requires
- php: >=7.2
- ext-ctype: *
- ext-gettext: *
- ext-iconv: *
- ext-json: *
- ext-mbstring: *
- ext-pcntl: *
- ext-posix: *
- vlucas/phpdotenv: ^3.3
Suggests
- ext-curl: *
- kakserpom/phpdaemon: dev-master
README
Данный раздел можно пропустить, но он рекомендуется разработчикам к прочтению.
Фреймворк исполнен минимализма и создан по трём базовым принципам — элегантность, производительность, прагматизм.
Производительность
PHP 7 замечательный язык с достойноной производительностью, но разработчики популярных фреймворков так увлеклись подменяемостью и универсальностью, попутно добавляя всё больше runtime-абстракций, что не заметили как перевернули всё с ног на голову. Зачастую можно видеть, что есть обширный Registry модулей, которые при каждом запросе перебираются поочередно и каждый что-то вносит в состояние.
В результате имеем то что имеем. Среднестатический сайт выдерживает от силы 50 запросов в секунду (без кеширования ответов в nginx) на выделенном сервере занимающем пару юнитов в стойке.
Принцип нулевого бутстрапа
Это backtrace из Hello world! контроллера, просто сравните его с вереницей вызовов в тех фреймворках, которые вам доводилось использовать. Вы будете удивлены.
1 0.0000 397392 {main}( ) .../index.php:0
2 0.0006 444616 Zer0\HTTP\HTTP->handleRequest( ) .../index.php:22
3 0.0008 520416 MyProject\HTTP\Controllers\Index->indexAction( ) .../HTTP.php:136
Мы не делаем лишних действий в runtime и не выполняем код без требования.
Например, у нас считается моветоном обращаться к сессии (считывать её из хранилища), если того не требует бизнес-логика выполнения данного конкретного HTTP-запроса. Равно как и обращаться к хранилищу сессий на запись, если в данных сессии не было изменений.
Composer реализован так, что подключенные зависимости могут бесстыдно добавлять файлы в безусловную автозагрузку, поэтому в папке cli отдельный composer.json для таких пакетов как phinx, которые не используются в веб-части. В cli производительность не играет никакой роли и там нет проблемы подключать всё что угодно, а основное приложение мы содержим в чистоте.
PHP больше не рождён умирать
Исторически PHP воспринимался как интерпретатор, который полностью сбрасывает своё состояние после завершения обработки запроса. Однако, намного более производительным вариантом является истинный FastCGI, когда bootstrap-фаза в рабочем процессе выполняется единожды и затем идёт последовательная обработка входящих запросов. Отсюда и приставка Fast в FastCGI. Классический же CGI лишён возможности проводить bootstrap-фазу единожды.
- Мы не используем exit() и die()
- Вместо Fatal error мы пользуемся исключениями.
- Константы не должны быть запросозависимыми.
Близость к PHP
В большинстве фреймворков (не будем тыкать пальцем), для обращения к параметру запроса несколько десятков классов, создать легион объектов и потом вызвать метод, который вызовет метод, который вызовет метод, который обратится к коллекции параметров запроса, проверит есть ли параметр и вернет значение или параметр $default. Это очень непроизводительность, неинтуитивно и громоздко
Мы пишем просто $_GET['name'] ?? 'John Doe'
.
Да, когда-то не было оператора ?? и приходилось либо тащить везде isset() либо использовать методы-хелперы.
Но те времена канули в лету.
Тесты
Unit и интеграционные тесты — это замечательно. Чем больше кода покрыто тестами, тем меньше шансов что-то сломать и не заметить. Однако, тесты должны быть быстрыми, а главное поддерживаешь многопоточное выполнение.
Прагматизм
Отношение к версиям PHP
Мы всегда ориентируемся на последнюю стабильную версию PHP (в данный момент это 7.2.10), поддержке более старых версий внимание не уделяется, так мы можем использовать последние новинки и при этом обойтись без условий с PHP_VERSION.
Code Style
Мы не тратим драгоценное время на то чтобы поддерживать стиль кода вручную, а также на споры о том какой стиль лучше.
Команда
make fmt
(цельfmt
также включена вall
) в dev-окружении автоматически форматирует все PHP, JS и CSS исходники.
Типизация
При разработке фреймворка мы почти во всех случаях придерживаемся принципа строгой типизации. То бишь у функций/методов должен быть задан тип аргументов, а также тип возвращаемого значения. Например,
public function validate(?string $token = null): bool
Это позволяет избежать множества багов. Также крайне желательно указывать declare(strict_types=1);
в начале каждого файла.
Мы не используем loose comparison
(операторы ==
и !=
) почти никогда. Редкое исключение — когда нужно сравнить два объекта
по типу и свойствам, а не по ссылке.
Также мы не приводим строки к boolean, float и integer по причине некорректного отождествления, которое сложилось в PHP исторически. Так,
php > var_dump(('1helloWorld' == 1);
bool(true)
Что может вести к нехорошим последствиям при обработке пользовательского ввода.
Брокеры
По своей сути они являются фабриками компонентов и библиотек.
Например, $app->factory('Redis')
вернет объект драйвера Redis с настройками взятыми из conf/Redis
.
Метод get() принимает необязательный параметр с именем конфигурации, что позволяет иметь несколько конфигураций
одного компонента.
Есть брокеры, которые хранят объект после первого создания, например, PDO
или SessionStorage
. Другие же, такие как Session
,
при каждом вызове get()
порождают новый объект.
Добавление собственного брокера
В конфигурацию Main нужно добавить:
brokers:
MyCustomBroker: \My\Custom\Broker
И создать соответующий класс наследующийся \Zer0\Brokers\Base.
Таким же образом можно подменить и брокеры, которые лежат в \Zer0\Brokers\*
и не нуждаются в объявлении в конфиге.